Some of the questions that can be answered with this dataset: 1. How is each TED Talk related to every other TED Talk? 2. Which are the most viewed and most favorited Talks of all time? Are they mostly the same? What does this tell us? 3. What kind of topics attract the maximum discussion and debate (in the form of comments)? 4. Which months are most popular among TED and TEDx chapters? 5. Which themes are most popular amongst TEDsters?

Read the data files

library(readr)
ted <- read_csv("ted-talks/ted_main.csv")
Parsed with column specification:
cols(
  comments = col_integer(),
  description = col_character(),
  duration = col_integer(),
  event = col_character(),
  film_date = col_integer(),
  languages = col_integer(),
  main_speaker = col_character(),
  name = col_character(),
  num_speaker = col_integer(),
  published_date = col_integer(),
  ratings = col_character(),
  related_talks = col_character(),
  speaker_occupation = col_character(),
  tags = col_character(),
  title = col_character(),
  url = col_character(),
  views = col_integer()
)
head(ted)
transcript <- read_csv("ted-talks/transcripts.csv")
Parsed with column specification:
cols(
  transcript = col_character(),
  url = col_character()
)
head(transcript)

See the information of both datasets

summary(ted)
    comments      description           duration         event             film_date           languages    
 Min.   :   2.0   Length:2550        Min.   : 135.0   Length:2550        Min.   :7.465e+07   Min.   : 0.00  
 1st Qu.:  63.0   Class :character   1st Qu.: 577.0   Class :character   1st Qu.:1.257e+09   1st Qu.:23.00  
 Median : 118.0   Mode  :character   Median : 848.0   Mode  :character   Median :1.333e+09   Median :28.00  
 Mean   : 191.6                      Mean   : 826.5                      Mean   :1.322e+09   Mean   :27.33  
 3rd Qu.: 221.8                      3rd Qu.:1046.8                      3rd Qu.:1.413e+09   3rd Qu.:33.00  
 Max.   :6404.0                      Max.   :5256.0                      Max.   :1.504e+09   Max.   :72.00  
 main_speaker           name            num_speaker    published_date        ratings          related_talks     
 Length:2550        Length:2550        Min.   :1.000   Min.   :1.151e+09   Length:2550        Length:2550       
 Class :character   Class :character   1st Qu.:1.000   1st Qu.:1.268e+09   Class :character   Class :character  
 Mode  :character   Mode  :character   Median :1.000   Median :1.341e+09   Mode  :character   Mode  :character  
                                       Mean   :1.028   Mean   :1.344e+09                                        
                                       3rd Qu.:1.000   3rd Qu.:1.423e+09                                        
                                       Max.   :5.000   Max.   :1.506e+09                                        
 speaker_occupation     tags              title               url                views         
 Length:2550        Length:2550        Length:2550        Length:2550        Min.   :   50443  
 Class :character   Class :character   Class :character   Class :character   1st Qu.:  755793  
 Mode  :character   Mode  :character   Mode  :character   Mode  :character   Median : 1124524  
                                                                             Mean   : 1698297  
                                                                             3rd Qu.: 1700760  
                                                                             Max.   :47227110  
summary(transcript)
  transcript            url           
 Length:2467        Length:2467       
 Class :character   Class :character  
 Mode  :character   Mode  :character  

Check the dimensions of the data

dim(ted)
[1] 2550   17
dim(transcript)
[1] 2467    2

Features Available - name: The official name of the TED Talk. Includes the title and the speaker. - title: The title of the talk - description: A blurb of what the talk is about. - main_speaker: The first named speaker of the talk. - speaker_occupation: The occupation of the main speaker. - num_speaker: The number of speakers in the talk. - duration: The duration of the talk in seconds. - event: The TED/TEDx event where the talk took place. - film_date: The Unix timestamp of the filming. - published_date: The Unix timestamp for the publication of the talk on TED.com - comments: The number of first level comments made on the talk. - tags: The themes associated with the talk. - languages: The number of languages in which the talk is available. - ratings: A stringified dictionary of the various ratings given to the talk (inspiring, fascinating, jaw dropping, etc.) - related_talks: A list of dictionaries of recommended talks to watch next. - url: The URL of the talk. - views: The number of views on the talk. I’m just going to reorder the columns in the order I’ve listed the features for my convenience (and OCD).

Let’s change the UNIX timestamps to human readable date

library(anytime)
ted$film_date <- anydate(ted$film_date)
ted$published_date <- anydate(ted$published_date)

Exploratory Data Analysis - Which talks are most and least viewed?

Which talks are most and least viewed?

library(dplyr)

Attaching package: 'dplyr'

The following objects are masked from 'package:stats':

    filter, lag

The following objects are masked from 'package:base':

    intersect, setdiff, setequal, union
ten_talks <- arrange(ted, views)
keeps <- c("title", "main_speaker", "views", "speaker_occupation", "film_date")
ten_talks <- subset(ten_talks, select = c("title", "main_speaker", "views", "speaker_occupation", "film_date"))
last_10_talks <- ten_talks[0:10,]
last_10_talks
ten_talks <- arrange(ted, desc(views))
ten_talks <- subset(ten_talks, select = c("title", "main_speaker", "views", "speaker_occupation", "film_date"))
top_10_talks <- ten_talks[0:10,]
top_10_talks

Observations Ken Robinson’s talk on Do Schools Kill Creativity? is the most popular TED Talk of all time with 47.2 million views. Also coincidentally, it is also one of the first talks to ever be uploaded on the TED Site (the main dataset is sorted by published date). Robinson’s talk is closely followed by Amy Cuddy’s talk on Your Body Language May Shape Who You Are. There are only 2 talks that have surpassed the 40 million mark and 4 talks that have crossed the 30 million mark. Let us make a bar chart to visualise these 15 talks in terms of the number of views they garnered.

Loading required package: lattice
Loading required package: plyr
--------------------------------------------------------------------------------------------------------------------
You have loaded plyr after dplyr - this is likely to cause problems.
If you need functions from both plyr and dplyr, please load plyr first, then dplyr:
library(plyr); library(dplyr)
--------------------------------------------------------------------------------------------------------------------

Attaching package: 'plyr'

The following objects are masked from 'package:dplyr':

    arrange, count, desc, failwith, id, mutate, rename, summarise, summarize

Distribution of Views

ted_small <- subset(ted, views < 0.4e7)
p3 <- ggplot(ted, aes(x=views)) + 
 geom_histogram(aes(y=..density..), colour="black", fill="white")+
 geom_density(alpha=.2, fill="#FF6666")
p4 <- ggplot(ted_small, aes(x=views)) +
  geom_histogram(aes(y=..density..), colour="black", fill="white")+
  geom_density(alpha=.2, fill="#FF6666")
multiplot(p3, p4, cols=2)

library(Hmisc)
Loading required package: survival
Loading required package: Formula

Attaching package: 'Hmisc'

The following objects are masked from 'package:plyr':

    is.discrete, summarize

The following objects are masked from 'package:dplyr':

    src, summarize

The following objects are masked from 'package:base':

    format.pval, units
describe(ted$views)
ted$views 
       n  missing distinct     Info     Mean      Gmd      .05      .10      .25      .50      .75      .90      .95 
    2550        0     2550        1  1698297  1562903   361142   484265   755793  1124524  1700760  3051913  4557041 

lowest :    50443    66668    82488   112321   115346, highest: 22270883 31168150 34309432 43155405 47227110

The average number of views on TED Talks in 1.6 million. and the median number of views is 1.12 million. This suggests a very high average level of popularity of TED Talks. We also notice that the majority of talks have views less than 4 million.

Comments Let’s analyze comments on the talks

describe(ted$comments)
ted$comments 
       n  missing distinct     Info     Mean      Gmd      .05      .10      .25      .50      .75      .90      .95 
    2550        0      559        1    191.6    197.6     24.0     35.9     63.0    118.0    221.8    393.1    586.1 

lowest :    2    3    5    6    7, highest: 2673 2877 3356 4553 6404
sd(ted$comments)
[1] 282.3152

Observations - On average, there are 191.5 comments on every TED Talk. Assuming the comments are constructive criticism, we can conclude that the TED Online Community is highly involved in discussions revolving TED Talks. - There is a huge standard deviation associated with the comments. In fact, it is even larger than the mean suggesting that the measures may be sensitive to outliers. We shall plot this to check the nature of the distribution. - The minimum number of comments on a talk is 2 and the maximum is 6404. The range is 6402.. The minimum number, though, may be as a result of the talk being posted extremely recently.

ted_small <- subset(ted, comments < 500)
p5 <- ggplot(ted, aes(x=comments)) + 
 geom_histogram(aes(y=..density..), colour="black", fill="white")+
 geom_density(alpha=.2, fill="#FF6666")
p6 <- ggplot(ted_small, aes(x=comments)) +
  geom_histogram(aes(y=..density..), colour="black", fill="white")+
  geom_density(alpha=.2, fill="#FF6666")
multiplot(p5, p6, cols=2)

From the plot above, we can see that the bulk of the talks have fewer than 500 comments. This clearly suggests that the mean obtained above has been heavily influenced by outliers. This is possible because the number of samples is only 2550 talks.

Another question that I am interested in is if the number of views is correlated with the number of comments. We should think that this is the case as more popular videos tend to have more comments. Let us find out.

scatter1 <- qplot(views,comments, data=ted)  + 
         scale_x_continuous(limits=c(min(ted$views),max(ted$views))) + 
         scale_y_continuous(limits=c(min(ted$comments),max(ted$comments))) + 
         geom_rug(col=rgb(.5,0,0,alpha=.2))
scatter1

vc_cor <- cor(ted$views, ted$comments)
print("Correlation between Views and Comments")
[1] "Correlation between Views and Comments"
vc_cor
[1] 0.5309387

As the scatterplot and the correlation matrix show, the pearson coefficient is slightly more than 0.5. This suggests a medium to strong correlation between the two quantities. This result was pretty expected as mentioned above. Let us now check the number of views and comments on the 10 most commented TED Talks of all time.

ten_talks <- arrange(ted, comments)
keeps <- c("title", "main_speaker", "views", "comments")
ten_talks <- subset(ten_talks, select = keeps)
last_10_talks <- ten_talks[0:10,]
last_10_talks
ten_talks <- arrange(ted, desc(comments))
ten_talks <- subset(ten_talks, select = keeps)
top_10_talks <- ten_talks[0:10,]
top_10_talks

As can be seen above, Richard Dawkins’ talk on Militant Atheism’ generated the greatest amount of discussion and opinions despite having significantly lesser views than Ken Robinson’s talk, which is second in the list. This raises some interesting questions.

Which talks tend to attract the largest amount of discussion?

To answer this question, we will define a new feature discussion quotient which is simply the ratio of the number of comments to the number of views. We will then check which talks have the largest discussion quotient.

ted$dis_quo <- ted$comments/ted$views
ten_talks <- arrange(ted, dis_quo)
keeps <- c("title", "main_speaker", "views", "comments", "dis_quo")
ten_talks <- subset(ten_talks, select = keeps)
last_10_talks <- ten_talks[0:10,]
last_10_talks
ten_talks <- arrange(ted, desc(dis_quo))
ten_talks <- subset(ten_talks, select = keeps)
top_10_talks <- ten_talks[0:10,]
top_10_talks

This analysis has actually raised extremely interesting insights. Half of the talks in the top 10 are on the lines of Faith and Religion. I suspect science and religion is still a very hotly debated topic even in the 21st century. We shall come back to this hypothesis in a later section.

The most discusses talk, though, is The Case for Same Sex Marriage (which has religious undertones). This is not that surprising considering the amount of debate the topic caused back in 2009 (the time the talk was filmed).

Analyzing TED talks by the month and the year

TED (especially TEDx) Talks tend to occur all throughout the year. Is there a hot month as far as TED is concerned? In other words, how are the talks distributed throughout the months since its inception? Let us find out.

ted$filming_month <- as.numeric(format(ted$film_date, format= "%m"))
ted$filming_year <- as.numeric(format(ted$film_date, format = "%Y"))
month_df <- as.data.frame(table(ted$filming_month))
colnames(month_df) <- c("Month", "Talks")
month_df$Month <- c("Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec")
#Turn your 'Month' column into a character vector
month_df$Month <- as.character(month_df$Month)
#Then turn it back into an ordered factor
month_df$Month <- factor(month_df$Month, levels=unique(month_df$Month))
p8 <- ggplot(data = month_df, aes(Month, Talks)) +
      geom_bar(position = "dodge", stat = "identity", color = "blue", fill="blue") +
      geom_text(aes(label = Talks), vjust = 1.6, color = "white", size = 3) +
      tilt_theme
p8

February is clearly the most popular month for TED Conferences whereas August and January are the least popular. February’s popularity is largely due to the fact that the official TED Conferences are held in February. Let us check the distribution for TEDx talks only.

tedx <- filter(ted, grepl("TEDx", ted$event, fixed = TRUE))
month_df <- as.data.frame(table(tedx$filming_month))
colnames(month_df) <- c("Month", "Talks")
month_df$Month <- c("Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec")
#Turn your 'Month' column into a character vector
month_df$Month <- as.character(month_df$Month)
#Then turn it back into an ordered factor
month_df$Month <- factor(month_df$Month, levels=unique(month_df$Month))
p9 <- ggplot(data = month_df, aes(Month, Talks)) +
      geom_bar(position = "dodge", stat = "identity", color = "red", fill="red") +
      geom_text(aes(label = Talks), vjust = 1.6, color = "white", size = 3) +
      tilt_theme
p9

As far as TEDx talks are concerned, November is the most popular month. However, we cannot take this result at face value as very few of the TEDx talks are actually uploaded to the TED website and therefore, it is entirely possible that the sample in our dataset is not at all representative of all TEDx talks. A slightly more accurate statement would be that the most popular TEDx talks take place the most in October and November.

The next question I’m interested in is the most popular days for conducting TED and TEDx conferences. The tools applied are very sensible to the procedure applied for months.

ted$film_weekday <- weekdays(as.Date(ted$film_date))
weekday_df <- as.data.frame(table(ted$film_weekday))
weekday_df
colnames(weekday_df) <- c("Weekday", "Talks")
weekday_df <- weekday_df[c(4,2,6,7,5,1,3),]
#Turn your 'Month' column into a character vector
weekday_df$Weekday <- as.character(weekday_df$Weekday)
#Then turn it back into an ordered factor
weekday_df$Weekday <- factor(weekday_df$Weekday, levels=unique(weekday_df$Weekday))
p10 <- ggplot(data = weekday_df, aes(factor(Weekday), Talks)) +
      geom_bar(position = "dodge", stat = "identity", color = "green", fill="green") +
      geom_text(aes(label = Talks), vjust = 1.6, color = "black", size = 3) +
      tilt_theme
p10

The distribution of days is almost a bell curve with Wednesday and Thursday being the most popular days and Sunday being the least popular. This is pretty interesting because I was of the opinion that most TED Conferences would happen sometime in the weekend.

Let us now visualize the number of TED talks through the years and check if our hunch that they have grown significantly is indeed true.

year_df <- as.data.frame(table(ted$filming_year))
year_df
colnames(year_df) <- c("Year", "Talks")
#Turn your 'Month' column into a character vector
#month_df$Month <- as.character(month_df$Month)
#Then turn it back into an ordered factor
#month_df$Month <- factor(month_df$Month, levels=unique(month_df$Month))
p11 <- ggplot(data = year_df, aes(Year, Talks, group = 1)) +
      geom_line(color = "blue") +
      geom_point() +
      geom_text(aes(label = Talks), vjust = 1.6, color = "black", size = 3) +
      tilt_theme
p11

Obervations - As expected, the number of TED Talks have gradually increased over the years since its inception in 1984. - There was a sharp increase in the number if talks in 2009. It might be interesting to know the reasons behind 2009 being the tipping point where the number of talks increased more than twofold. - The number of talks have been pretty much constant since 2009.

Finally, to put it all together, let us construct a heat map that shows us the number of talks by month and year. This will give us a good summary of the distribution of talks.

keeps <- c("filming_month", "filming_year")
heatmap_df <- ted %>% subset(select = keeps) %>% arrange(filming_year)
heatmap_df <- as.data.frame(table(heatmap_df))
heatmap_df$filming_month <- month.abb[heatmap_df$filming_month]
heatmap_df$filming_month <- as.character(heatmap_df$filming_month)
heatmap_df$filming_month <- factor(heatmap_df$filming_month, levels=unique(month_df$Month))
#heatmap_df 
ggplot(heatmap_df, aes(filming_year, factor(filming_month))) +
  geom_tile(aes(fill = Freq), color = "white") +
  geom_text(aes(fill = heatmap_df$Freq, label = heatmap_df$Freq)) +
  scale_fill_gradient2(low = "darkred", 
                       mid = "white", 
                       high = "midnightblue", 
                       midpoint = round(mean(heatmap_df$Freq))) +
  ylab("Year") +
  xlab("Months") +
  theme(legend.title = element_text(size = 10),
        legend.text = element_text(size = 12),
        plot.title = element_text(size=16),
        axis.title=element_text(size=14,face="bold"),
        axis.text.x = element_text(angle = 90, hjust = 1)) +
  labs(fill = "Freq")
Ignoring unknown aesthetics: fill

Ted Speakers

In this section, we will try and gain insight about all the amazing speakers who have managed to inspire millions of people through their talks on the TED Platform. The first question we shall ask in this section is who are the most popular TED Speakers. That is, which speakers have given the most number of TED Talks.

speaker_df <- as.data.frame(table(ted$main_speaker))
speaker_df <- arrange(speaker_df, desc(Freq))
speaker_df

Hans Rosling, the Swiss Health Professor is clearly the most popular TED Speaker, with more than 9 appearances on the TED Forum. Juan Enriquez comes a close second with 7 appearances. Rives and Marco Tempest have graced the TED platform 6 times.

Which occupation should you choose if you want to become a TED Speaker? Let us have a look what kind of people TED is most interested in inviting to its events.

occupation_df <- as.data.frame(table(ted$speaker_occupation))
occupation_df <- arrange(occupation_df, desc(Freq))
occupation_df <- head(occupation_df, 10)
colnames(occupation_df) <- c("Occupation", "Appearances")
occupation_df$Occupation <- as.character(occupation_df$Occupation)
occupation_df$Occupation <- factor(occupation_df$Occupation, levels=occupation_df$Occupation)
p12 <- ggplot(data = occupation_df, aes(factor(Occupation), Appearances)) +
      geom_bar(position = "dodge", stat = "identity", color = "cyan", fill="cyan") +
      geom_text(aes(label = Appearances), vjust = 1.6, color = "black", size = 3) +
      tilt_theme
p12

Observations - Writers are the most popular with more than 45 speakers identifying themselves as the aforementioned. - Artists and Designers come a distant second with around 35 speakers in each category. - This result must be taken with a pinch of salt as a considerable number of speakers identify themselves with multiple professions (for example, writer/entrepreneur).

Do some professions tend to attract a larger number of viewers? Do answer this question let us visualise the relationship between the top 10 most popular professions and the views that garnered in the form of a box plot.

top_occupation_views <- filter(ted, ted$speaker_occupation %in% occupation_df$Occupation)
p13 <- ggplot(top_occupation_views, aes(x=speaker_occupation, y=views)) + 
  geom_boxplot() +
  geom_jitter(shape=16, position=position_jitter(0.2)) +
  tilt_theme
p13 

On average, out of the top 10 most popular professions, Psychologists tend to garner the most views. Writers have the greatest range of views between the first and the third quartile..

Finally, let us check the number of talks which have had more than one speaker.

speaker_count <- table(ted$num_speaker)
speaker_count

   1    2    3    4    5 
2492   49    5    3    1 

Almost every talk has just one speaker. There are close to 50 talks where two people shared the stage. The maximum number of speakers to share a single stage was 5. I suspect this was a dance performance. Let’s have a look.

filter(ted, ted$num_speaker==5)

My hunch was correct. It is a talk titled A dance to honor Mother Earth by Jon Boogz and Lil Buck at the TED 2017 Conference.

TED Events Which TED Events tend to hold the most number of TED.com upload worthy events? We will try to answer that question in this section.

events_df <- ted %>% select(c("event")) %>% group_by("event")
events_df <- as.data.frame(table(events_df))
events_df <- arrange(events_df, desc(Freq))
events_df <- head(events_df, 10)
p14 <- ggplot(data = events_df, aes(event, Freq)) +
      geom_bar(position = "dodge", stat = "identity", color = "blue", fill="blue") +
      geom_text(aes(label = Freq), vjust = 1.6, color = "white", size = 3) +
      tilt_theme
p14

As expected, the official TED events held the major share of TED Talks published on the TED.com platform. TED2014 had the most number of talks followed by TED2009. There isn’t too much insight to be gained from this.

TED Languages One remarkable aspect of TED Talks is the sheer number of languages in which it is accessible. Let us perform some very basic data visualisation and descriptive statistics about languages at TED.

describe(ted$languages)
ted$languages 
       n  missing distinct     Info     Mean      Gmd      .05      .10      .25      .50      .75      .90      .95 
    2550        0       66    0.998    27.33    10.11        7       18       23       28       33       38       41 

lowest :  0  1  2  3  4, highest: 64 65 66 69 72

On average, a TED Talk is available in 27 different languages. The maximum number of languages a TED Talk is available in is a staggering 72. Let us check which talk this is.

filter(ted, ted$languages == 72)

The most translated TED Talk of all time is Matt Cutts’ Try Something New in 30 Days. The talk does have a very universal theme of exploration. The sheer number of languages it’s available in demands a little more inspection though as it has just over 8 million views, far fewer than the most popular TED Talks.

Finally, let us check if there is a correlation between the number of views and the number of languages a talk is availbale in. We would think that this should be the case since the talk is more accessible to a larger number of people but as Matt Cutts’ talk shows, it may not really be the case.

scatter2 <- qplot(languages, views, data=ted)  + 
         scale_y_continuous(limits=c(min(ted$views),max(ted$views))) + 
         scale_x_continuous(limits=c(min(ted$languages),max(ted$languages))) + 
         geom_rug(col=rgb(.5,0,0,alpha=.2))
scatter2

cor(ted$languages, ted$views)
[1] 0.3776231

The Pearson coefficient is 0.38 suggesting a medium correlation between the aforementioned quantities.

TED Themes In this section, we will try to find out the most popular themes in the TED conferences. Although TED started out as a conference about technology, entertainment and design, it has since diversified into virtually every field of study and walk of life. It will be interesting to see if this conference with Silicon Valley origins has a bias towards certain topics.

To answer this question, we need to wrangle our data in a way that it is suitable for analysis. More specifically, we need to split the related_tags list into separate rows.

perfect_tag <- function(x){
  x <- unlist(strsplit(x, "'"))
  val = x[2]
  for (i in 3:length(x))
    if (nchar(x[i]) >2)
      val <- c(val, x[i])
    return (val)
  
}
ted$processed_tags <-  lapply(ted$tags, perfect_tag)
processed_tags <- ted$processed_tags
length(processed_tags)
[1] 2550
processed_tags <- unlist(processed_tags, recursive=FALSE)
length(processed_tags)
[1] 19154
processed_tags <- as.data.frame(table(processed_tags))
processed_tags <- arrange(processed_tags, desc(Freq))
head(processed_tags, 10)
processed_tags$processed_tags <- as.character(processed_tags$processed_tags)
processed_tags$processed_tags <- factor(processed_tags$processed_tags, levels=processed_tags$processed_tags)
p15 <- ggplot(data = head(processed_tags, 10), aes(processed_tags, Freq)) +
      geom_bar(position = "dodge", stat = "identity", color = "blue", fill="blue") +
      geom_text(aes(label = Freq), vjust = 1.6, color = "white", size = 3) +
      tilt_theme
p15

As may have been expected, Technology is the most popular topic for talks. The other two original factions, Design and Entertainment, also make it to the list of top 10 themes. Science and Global Issues are the second and the third most popular themes respectively.

The next question I want to answer is the trends in the share of topics of TED Talks across the world. Has the demand for Technology talks increased? Do certain years have a disproportionate share of talks related to global issues? Let’s find out!

We will only be considering the top 7 themes, excluding TEDx and talks after 2009, the year when the number of TED Talks really peaked.

factor_fn <- function(x){
  return(factor(x, levels = x))
}
ted$processed_tags <- lapply(ted$processed_tags, unlist, recursive = FALSE)
ted$processed_tags <- lapply(ted$processed_tags, factor_fn)
rows_to_keep <- rep(TRUE, length(ted$processed_tags))
for (i in 1:length(ted$processed_tags)){
  if (any(unlist(ted$processed_tags[i]) %in% processed_tags$processed_tags[1:10])){
    rows_to_keep[i] <- TRUE} else {
    rows_to_keep[i] <- FALSE}
}
pop_theme_talks <- subset(pop_theme_talks, filming_year>2008)
pop_theme_talks <- pop_theme_talks[rows_to_keep,]
themes <- list(processed_tags$processed_tags[1:10])
themes
[[1]]
 [1] technology    science       global issues culture       TEDx          design        business      entertainment
 [9] health        innovation   
416 Levels: technology science global issues culture TEDx design business entertainment health innovation ... testing
colnames(pop_theme_talks)
 [1] "name"           "event"          "views"          "filming_month"  "filming_year"   "processed_tags"
 [7] "technology"     "science"        "gi"             "culture"        "tedx"           "design"        
[13] "business"       "et"             "health"         "inno"           "dummy"         
# drop columns
pop_theme_talks <- pop_theme_talks[, c("name", "event", "views", "filming_month", "filming_year", "processed_tags")]
pop_theme_talks
x <- unlist(pop_theme_talks$processed_tags[4])
toString(x[3])
[1] "global issues"
#tag <- "technology"
#tag <- "science"
#tag <- "global issues"
#tag <- "culture"
#tag <-  "TEDx"
#tag <- "design"
#tag <- "business"
#tag <-  "entertainment"
#tag <- "health"
#tag <- "innovation""
count_tag <- function(vec, tag){
  count <- 0
  x<- unlist(vec)
  for (i in 1:length(x)){
    if (toString(x[i]) == tag){
      count <- count+1
    }
  }
  return (count)
}
pop_theme_talks$technology <- sapply(X = pop_theme_talks$processed_tags,FUN = count_tag, tag = "technology")
pop_theme_talks$science <- sapply(X = pop_theme_talks$processed_tags,FUN = count_tag, tag = "science")
pop_theme_talks$gi <- sapply(X = pop_theme_talks$processed_tags,FUN = count_tag, tag = "global issues")
pop_theme_talks$culture <- sapply(X = pop_theme_talks$processed_tags,FUN = count_tag, tag = "culture")
pop_theme_talks$tedx <- sapply(X = pop_theme_talks$processed_tags,FUN = count_tag, tag = "TEDx")
pop_theme_talks$design <- sapply(X = pop_theme_talks$processed_tags,FUN = count_tag, tag = "design")
pop_theme_talks$business <- sapply(X = pop_theme_talks$processed_tags,FUN = count_tag, tag = "business")
pop_theme_talks$et <- sapply(X = pop_theme_talks$processed_tags,FUN = count_tag, tag = "entertainment")
pop_theme_talks$health <- sapply(X = pop_theme_talks$processed_tags,FUN = count_tag, tag = "health")
pop_theme_talks$inno <- sapply(X = pop_theme_talks$processed_tags,FUN = count_tag, tag = "innovation")
tag1 <- as.data.frame(table(pop_theme_talks$filming_year, pop_theme_talks$technology)[,2])
tag2 <- as.data.frame(table(pop_theme_talks$filming_year, pop_theme_talks$science)[,2])
tag3 <- as.data.frame(table(pop_theme_talks$filming_year, pop_theme_talks$gi)[,2])
tag4 <- as.data.frame(table(pop_theme_talks$filming_year, pop_theme_talks$culture)[,2])
tag5 <- as.data.frame(table(pop_theme_talks$filming_year, pop_theme_talks$tedx)[,2])
tag6 <- as.data.frame(table(pop_theme_talks$filming_year, pop_theme_talks$design)[,2])
tag7 <- as.data.frame(table(pop_theme_talks$filming_year, pop_theme_talks$business)[,2])
tag8 <- as.data.frame(table(pop_theme_talks$filming_year, pop_theme_talks$et)[,2])
tag9 <- as.data.frame(table(pop_theme_talks$filming_year, pop_theme_talks$health)[,2])
tag10 <- as.data.frame(table(pop_theme_talks$filming_year, pop_theme_talks$inno)[,2])
tag_df <- cbind.data.frame(tag1, tag2, tag3, tag4, tag5, tag6, tag7, tag8, tag9, tag10)
#tag_df$filming_year <- as.numeric(rownames(tag_df))
tag_df <- as.data.frame(t(tag_df))
#colnames(tag_df) <- tag_df[1, ]
#tag_df<- tag_df[-1, ]
#tag_df$myfactor <- factor(row.names(tag_df))
tag_df
library(reshape2)
library (scales)

Attaching package: 'scales'

The following object is masked from 'package:readr':

    col_factor
tag_df$row <- seq_len(nrow(tag_df))
dat2 <- melt(tag_df, id.vars = "row")
dat2$tag <- rep(c("technology","science","global issues", "culture", "TEDx", "design", "business", "entertainment",
                  "health","innovation"), 9)
p16 <- ggplot(dat2, aes(x=variable, y=value, fill=tag)) + 
  geom_bar(stat="identity", position = "fill") +
  xlab("\nYear") +
  ylab("Percentage\n") +
  scale_y_continuous(labels = percent_format()) +
  tilt_theme
p16

head(dat2)
p17 <- ggplot(dat2, aes(x=variable, y=value, colour=tag)) + 
  geom_point(aes(x=variable, y=value, color=tag, size = tag)) +
  tilt_theme
p17

The proportion of technology talks has steadily increased over the years with a slight dip in 2010. This is understandable considering the boom of technologies such as blockchain, deep learning and augmented reality capturing people’s imagination.

Talks on culture have witnessed a dip, decreasing steadily starting 2013. The share of culture talks has been the least in 2017. Entertainment talks also seem to have witnessed a slight decline in popularity since 2009.

Talk Duration and Word Counts

In this section, we will perform analysis on the length of TED Talks. TED is famous for imposing a very strict time limit of 18 minutes. Although this is the suggested limit, there have been talks as short as 2 minutes and some have stretched to as long as 24 minutes. Let us get an idea of the distribution of TED Talk durations.

ted$duration <- ted$duration /60
describe(ted$duration)
ted$duration 
       n  missing distinct     Info     Mean      Gmd      .05      .10      .25      .50      .75      .90      .95 
    2550        0     1083        1    13.78    6.466    4.491    5.833    9.617   14.133   17.446   19.833   21.759 

lowest :  2.250000  2.333333  2.350000  2.383333  2.550000, highest: 59.550000 60.133333 65.916667 76.450000 87.600000

TED Talks, on average are 13.7 minutes long. I find this statistic surprising because TED Talks are often synonymous with 18 minutes and the average is a good 3 minutes shorter than that.

The shortest TED Talk on record is 2.25 minutes long whereas the longest talk is 87.6 minutes long. I’m pretty sure the longest talk was not actually a TED Talk. Let us look at both the shortest and the longest talk

filter(ted, ted$duration == 2.25)
filter(ted, ted$duration == 2.25)

The shortest talk was at TED2007 titled The ancestor of language by Murray Gell-Mann. The longest talk on TED.com, as we had guessed, is not a TED Talk at all. Rather, it was a talk titled Parrots, the universe and everything delivered by Douglas Adams at the University of California in 2001.

Let us now check for any correlation between the popularity and the duration of a TED Talk. To make sure we only include TED Talks, we will consider only those talks which have a duration less than 25 minutes

scatter3 <- qplot(duration, views, data=filter(ted, ted$duration < 25))  + 
         scale_y_continuous(limits=c(min(ted$views),max(ted$views))) + 
         scale_x_continuous(limits=c(min(ted$duration),25)) + 
         geom_rug(col=rgb(.5,0,0,alpha=.2))
scatter3

z <- filter(ted, ted$duration <25)
vd_cor <- cor(z$views, z$duration)
print("Correlation between Views and duration")
[1] "Correlation between Views and duration"
vd_cor
[1] 0.07582871

There seems to be almost no correlation between these two quantities. This strongly suggests that there is no tangible correlation between the length and the popularity of a TED Talk. Content is king at TED.

Next, we look at transcripts to get an idea of word count. For this, we introduce our second dataset, the one which contains all transcripts.

head(transcript)
dim(transcript)
[1] 2467    2

It seems that we have data available for 2467 talks. Let us perform a join of the two dataframes on the url feature to include word counts for every talk.

df_ted <- left_join(ted, transcript, by = "url")
head(df_ted)
library(stringr)
df_ted$transcript <- replace(df_ted$transcript,is.na(df_ted$transcript),' ')
count_words <- function(vec){
  return (length(unlist((str_extract_all(tolower(vec), '\\w+')))))
}
df_ted$word_count <- sapply(df_ted$transcript, count_words)
describe(df_ted$word_count)
df_ted$word_count 
       n  missing distinct     Info     Mean      Gmd      .05      .10      .25      .50      .75      .90      .95 
    2553        0     1799        1     2052     1179    331.6    681.6   1287.0   2060.0   2785.0   3322.2   3655.2 

lowest :    0    2    3    4    7, highest: 6023 6324 6723 8278 9418

We can see that the average TED Talk has around 1971 words and there is a significantly large standard deviation of a 1009 words. The longest talk is more than 9044 words in length.

Like duration, there shouldn’t be any correlation between number of words and views. We will proceed to look at a more interesting statstic: the number of words per minute.

df_ted$wpm <- df_ted$word_count/df_ted$duration
describe(df_ted$wpm)
df_ted$wpm 
       n  missing distinct     Info     Mean      Gmd      .05      .10      .25      .50      .75      .90      .95 
    2553        0     2453        1      148    40.77     55.0    110.1    136.1    154.7    172.1    187.3    196.8 

lowest :   0.0000000   0.2033898   0.4278075   0.6185567   0.6469003
highest: 224.5989305 227.9180887 230.8424182 233.7215190 257.8378378

The average TED Speaker enunciates 142 words per minute. The fastest talker spoke a staggering 247 words a minute which is much higher than the average of 125-150 words per minute in English. Let us see who this is!

filter(df_ted, df_ted$wpm > 245)

Finally, in this section, I’d like to see if there is any correlation between words per minute and popularity.

scatter4 <- qplot(wpm, views, data=filter(df_ted, df_ted$duration<25))  + 
         scale_y_continuous(limits=c(min(df_ted$views),max(df_ted$views))) + 
         scale_x_continuous(limits=c(min(df_ted$wpm),max(df_ted$wpm))) + 
         geom_rug(col=rgb(.5,0,0,alpha=.2))
scatter4

z <- filter(df_ted, df_ted$duration<25)
vd_cor <- cor(z$views, z$wpm)
print("Correlation between Views and words per minute")
[1] "Correlation between Views and words per minute"
vd_cor
[1] 0.07340039

Again, there is practically no correlation. If you are going to give a TED Talk, you probably shouldn’t worry if you’re speaking a little faster or a little slower than usual.

TED Ratings TED allows its users to rate a particular talk on a variety of metrics. We therefore have data on how many people found a particular talk funny, inspiring, creative and a myriad of other verbs. Let us inspect how this ratings dictionary actually looks like.

rating_to_list <- function(vec){
x <- str_extract_all(vec, "\\w+")
x <- str_replace_all(x, "id", " ")
x <- str_replace_all(x, "name", " ")
x <- str_replace_all(x, "count", " ")
x <- unlist(str_extract_all(x, "\\w+"))
x <- setdiff(x, "c")
return (x)
}
ted$rat_list <- lapply(ted$ratings, rating_to_list)
unlist(ted$rat_list[1])
 [1] "7"            "Funny"        "19645"        "1"            "Beautiful"    "4573"         "9"           
 [8] "Ingenious"    "6073"         "3"            "Courageous"   "3253"         "11"           "Longwinded"  
[15] "387"          "2"            "Confusing"    "242"          "8"            "Informative"  "7346"        
[22] "22"           "Fascinating"  "10581"        "21"           "Unconvincing" "300"          "24"          
[29] "Persuasive"   "10704"        "23"           "Jaw"          "dropping"     "4439"         "25"          
[36] "OK"           "1174"         "26"           "Obnoxious"    "209"          "10"           "Inspiring"   
[43] "24924"       
which(unlist(ted$rat_list[1]) == "Beautiful")
[1] 5
unlist(ted$rat_list[1])[which(unlist(ted$rat_list[1]) == "Beautiful")+1]
[1] "4573"

In this section, I want to find out which talks were rated the funniest, the most beautiful, the most confusing and most jaw dropping of all time. The rest is left to the reader to explore. We now need to define three extra features to accomplish this task.

find_rating_count <- function(vec, rat_tag){
  count <- unlist(vec)[which(unlist(vec) == rat_tag) +1]
  return (count)
}
ted$funny <- sapply(ted$rat_list, find_rating_count, rat_tag = "Funny")
ted$funny <- replace(ted$funny,is.na(ted$funny),"0")
ted$funny <- as.numeric(ted$funny)
NAs introduced by coercion
ted$funny <- replace(ted$funny,is.na(ted$funny),0)
ted$beautiful <- sapply(ted$rat_list, find_rating_count, rat_tag = "Beautiful")
ted$beautiful <- replace(ted$beautiful,is.na(ted$beautiful),"0")
ted$beautiful <- as.numeric(ted$beautiful)
NAs introduced by coercion
ted$beautiful <- replace(ted$beautiful,is.na(ted$beautiful),0)
ted$confusing <- sapply(ted$rat_list, find_rating_count, rat_tag = "Confusing")
ted$confusing <- replace(ted$confusing,is.na(ted$confusing),"0")
ted$confusing <- as.numeric(ted$confusing)
NAs introduced by coercion
ted$confusing <- replace(ted$confusing,is.na(ted$confusing),0)
ted$jawdropping <- sapply(ted$rat_list, find_rating_count, rat_tag = "dropping")
ted$jawdropping <- replace(ted$jawdropping,is.na(ted$jawdropping),"0")
ted$jawdropping <- as.numeric(ted$jawdropping)
NAs introduced by coercion
ted$jawdropping <- replace(ted$jawdropping,is.na(ted$jawdropping),0)
head(ted)

Funniest talk of all time

ten_talks <- arrange(ted, funny)
keeps <- c("title", "main_speaker", "views", "speaker_occupation", "film_date")
ten_talks <- subset(ten_talks, select = c("title", "main_speaker", "views", "funny", "film_date"))
last_10_talks <- ten_talks[0:10,]
last_10_talks
ten_talks <- arrange(ted, desc(funny))
ten_talks <- subset(ten_talks, select = c("title", "main_speaker", "views", "funny", "film_date"))
top_10_talks <- ten_talks[0:10,]
top_10_talks

Most Beautiful Talks of all time

ten_talks <- arrange(ted, desc(beautiful))
ten_talks <- subset(ten_talks, select = c("title", "main_speaker", "views", "beautiful", "film_date"))
top_10_talks <- ten_talks[0:10,]
top_10_talks

Most Jaw Dropping Talks of all time

ten_talks <- arrange(ted, desc(jawdropping))
ten_talks <- subset(ten_talks, select = c("title", "main_speaker", "views", "jawdropping", "film_date"))
top_10_talks <- ten_talks[0:10,]
top_10_talks

Most Confusing Talks of all time

ten_talks <- arrange(ted, desc(confusing))
ten_talks <- subset(ten_talks, select = c("title", "main_speaker", "views", "confusing", "film_date"))
top_10_talks <- ten_talks[0:10,]
top_10_talks
LS0tCnRpdGxlOiAiVGVkIFRhbGsiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KClNvbWUgb2YgdGhlIHF1ZXN0aW9ucyB0aGF0IGNhbiBiZSBhbnN3ZXJlZCB3aXRoIHRoaXMgZGF0YXNldDogMS4gSG93IGlzIGVhY2ggVEVEIFRhbGsgcmVsYXRlZCB0byBldmVyeSBvdGhlciBURUQgVGFsaz8gMi4gV2hpY2ggYXJlIHRoZSBtb3N0IHZpZXdlZCBhbmQgbW9zdCBmYXZvcml0ZWQgVGFsa3Mgb2YgYWxsIHRpbWU/IEFyZSB0aGV5IG1vc3RseSB0aGUgc2FtZT8gV2hhdCBkb2VzIHRoaXMgdGVsbCB1cz8gMy4gV2hhdCBraW5kIG9mIHRvcGljcyBhdHRyYWN0IHRoZSBtYXhpbXVtIGRpc2N1c3Npb24gYW5kIGRlYmF0ZSAoaW4gdGhlIGZvcm0gb2YgY29tbWVudHMpPyA0LiBXaGljaCBtb250aHMgYXJlIG1vc3QgcG9wdWxhciBhbW9uZyBURUQgYW5kIFRFRHggY2hhcHRlcnM/IDUuIFdoaWNoIHRoZW1lcyBhcmUgbW9zdCBwb3B1bGFyIGFtb25nc3QgVEVEc3RlcnM/CgpSZWFkIHRoZSBkYXRhIGZpbGVzCgpgYGB7cn0KbGlicmFyeShyZWFkcikKdGVkIDwtIHJlYWRfY3N2KCJ0ZWQtdGFsa3MvdGVkX21haW4uY3N2IikKaGVhZCh0ZWQpCmBgYAoKYGBge3J9CnRyYW5zY3JpcHQgPC0gcmVhZF9jc3YoInRlZC10YWxrcy90cmFuc2NyaXB0cy5jc3YiKQpoZWFkKHRyYW5zY3JpcHQpCmBgYAoKU2VlIHRoZSBpbmZvcm1hdGlvbiBvZiBib3RoIGRhdGFzZXRzCgpgYGB7cn0Kc3VtbWFyeSh0ZWQpCmBgYAoKYGBge3J9CnN1bW1hcnkodHJhbnNjcmlwdCkKYGBgCgpDaGVjayB0aGUgZGltZW5zaW9ucyBvZiB0aGUgZGF0YQpgYGB7cn0KZGltKHRlZCkKZGltKHRyYW5zY3JpcHQpCmBgYAoKRmVhdHVyZXMgQXZhaWxhYmxlCi0gbmFtZTogVGhlIG9mZmljaWFsIG5hbWUgb2YgdGhlIFRFRCBUYWxrLiBJbmNsdWRlcyB0aGUgdGl0bGUgYW5kIHRoZSBzcGVha2VyLgotIHRpdGxlOiBUaGUgdGl0bGUgb2YgdGhlIHRhbGsKLSBkZXNjcmlwdGlvbjogQSBibHVyYiBvZiB3aGF0IHRoZSB0YWxrIGlzIGFib3V0LgotIG1haW5fc3BlYWtlcjogVGhlIGZpcnN0IG5hbWVkIHNwZWFrZXIgb2YgdGhlIHRhbGsuCi0gc3BlYWtlcl9vY2N1cGF0aW9uOiBUaGUgb2NjdXBhdGlvbiBvZiB0aGUgbWFpbiBzcGVha2VyLgotIG51bV9zcGVha2VyOiBUaGUgbnVtYmVyIG9mIHNwZWFrZXJzIGluIHRoZSB0YWxrLgotIGR1cmF0aW9uOiBUaGUgZHVyYXRpb24gb2YgdGhlIHRhbGsgaW4gc2Vjb25kcy4KLSBldmVudDogVGhlIFRFRC9URUR4IGV2ZW50IHdoZXJlIHRoZSB0YWxrIHRvb2sgcGxhY2UuCi0gZmlsbV9kYXRlOiBUaGUgVW5peCB0aW1lc3RhbXAgb2YgdGhlIGZpbG1pbmcuCi0gcHVibGlzaGVkX2RhdGU6IFRoZSBVbml4IHRpbWVzdGFtcCBmb3IgdGhlIHB1YmxpY2F0aW9uIG9mIHRoZSB0YWxrIG9uIFRFRC5jb20KLSBjb21tZW50czogVGhlIG51bWJlciBvZiBmaXJzdCBsZXZlbCBjb21tZW50cyBtYWRlIG9uIHRoZSB0YWxrLgotIHRhZ3M6IFRoZSB0aGVtZXMgYXNzb2NpYXRlZCB3aXRoIHRoZSB0YWxrLgotIGxhbmd1YWdlczogVGhlIG51bWJlciBvZiBsYW5ndWFnZXMgaW4gd2hpY2ggdGhlIHRhbGsgaXMgYXZhaWxhYmxlLgotIHJhdGluZ3M6IEEgc3RyaW5naWZpZWQgZGljdGlvbmFyeSBvZiB0aGUgdmFyaW91cyByYXRpbmdzIGdpdmVuIHRvIHRoZSB0YWxrIChpbnNwaXJpbmcsIGZhc2NpbmF0aW5nLCBqYXcgZHJvcHBpbmcsIGV0Yy4pCi0gcmVsYXRlZF90YWxrczogQSBsaXN0IG9mIGRpY3Rpb25hcmllcyBvZiByZWNvbW1lbmRlZCB0YWxrcyB0byB3YXRjaCBuZXh0LgotIHVybDogVGhlIFVSTCBvZiB0aGUgdGFsay4KLSB2aWV3czogVGhlIG51bWJlciBvZiB2aWV3cyBvbiB0aGUgdGFsay4KSSdtIGp1c3QgZ29pbmcgdG8gcmVvcmRlciB0aGUgY29sdW1ucyBpbiB0aGUgb3JkZXIgSSd2ZSBsaXN0ZWQgdGhlIGZlYXR1cmVzIGZvciBteSBjb252ZW5pZW5jZSAoYW5kIE9DRCkuCgpMZXQncyBjaGFuZ2UgdGhlIFVOSVggdGltZXN0YW1wcyB0byBodW1hbiByZWFkYWJsZSBkYXRlCgpgYGB7cn0KbGlicmFyeShhbnl0aW1lKQp0ZWQkZmlsbV9kYXRlIDwtIGFueWRhdGUodGVkJGZpbG1fZGF0ZSkKdGVkJHB1Ymxpc2hlZF9kYXRlIDwtIGFueWRhdGUodGVkJHB1Ymxpc2hlZF9kYXRlKQpgYGAKCkV4cGxvcmF0b3J5IERhdGEgQW5hbHlzaXMKLSBXaGljaCB0YWxrcyBhcmUgbW9zdCBhbmQgbGVhc3Qgdmlld2VkPwoKCgpXaGljaCB0YWxrcyBhcmUgbW9zdCBhbmQgbGVhc3Qgdmlld2VkPwoKYGBge3J9CmxpYnJhcnkoZHBseXIpCgp0ZW5fdGFsa3MgPC0gYXJyYW5nZSh0ZWQsIHZpZXdzKQprZWVwcyA8LSBjKCJ0aXRsZSIsICJtYWluX3NwZWFrZXIiLCAidmlld3MiLCAic3BlYWtlcl9vY2N1cGF0aW9uIiwgImZpbG1fZGF0ZSIpCnRlbl90YWxrcyA8LSBzdWJzZXQodGVuX3RhbGtzLCBzZWxlY3QgPSBjKCJ0aXRsZSIsICJtYWluX3NwZWFrZXIiLCAidmlld3MiLCAic3BlYWtlcl9vY2N1cGF0aW9uIiwgImZpbG1fZGF0ZSIpKQoKbGFzdF8xMF90YWxrcyA8LSB0ZW5fdGFsa3NbMDoxMCxdCmxhc3RfMTBfdGFsa3MKCnRlbl90YWxrcyA8LSBhcnJhbmdlKHRlZCwgZGVzYyh2aWV3cykpCnRlbl90YWxrcyA8LSBzdWJzZXQodGVuX3RhbGtzLCBzZWxlY3QgPSBjKCJ0aXRsZSIsICJtYWluX3NwZWFrZXIiLCAidmlld3MiLCAic3BlYWtlcl9vY2N1cGF0aW9uIiwgImZpbG1fZGF0ZSIpKQp0b3BfMTBfdGFsa3MgPC0gdGVuX3RhbGtzWzA6MTAsXQp0b3BfMTBfdGFsa3MKYGBgCgpPYnNlcnZhdGlvbnMKS2VuIFJvYmluc29uJ3MgdGFsayBvbiBEbyBTY2hvb2xzIEtpbGwgQ3JlYXRpdml0eT8gaXMgdGhlIG1vc3QgcG9wdWxhciBURUQgVGFsayBvZiBhbGwgdGltZSB3aXRoIDQ3LjIgbWlsbGlvbiB2aWV3cy4KQWxzbyBjb2luY2lkZW50YWxseSwgaXQgaXMgYWxzbyBvbmUgb2YgdGhlIGZpcnN0IHRhbGtzIHRvIGV2ZXIgYmUgdXBsb2FkZWQgb24gdGhlIFRFRCBTaXRlICh0aGUgbWFpbiBkYXRhc2V0IGlzIHNvcnRlZCBieSBwdWJsaXNoZWQgZGF0ZSkuClJvYmluc29uJ3MgdGFsayBpcyBjbG9zZWx5IGZvbGxvd2VkIGJ5IEFteSBDdWRkeSdzIHRhbGsgb24gWW91ciBCb2R5IExhbmd1YWdlIE1heSBTaGFwZSBXaG8gWW91IEFyZS4KVGhlcmUgYXJlIG9ubHkgMiB0YWxrcyB0aGF0IGhhdmUgc3VycGFzc2VkIHRoZSA0MCBtaWxsaW9uIG1hcmsgYW5kIDQgdGFsa3MgdGhhdCBoYXZlIGNyb3NzZWQgdGhlIDMwIG1pbGxpb24gbWFyay4KTGV0IHVzIG1ha2UgYSBiYXIgY2hhcnQgdG8gdmlzdWFsaXNlIHRoZXNlIDE1IHRhbGtzIGluIHRlcm1zIG9mIHRoZSBudW1iZXIgb2Ygdmlld3MgdGhleSBnYXJuZXJlZC4KCmBgYHtyIGZpZy53aWR0aD03LCBmaWcuaGVpZ2h0PTQsIGVjaG89RkFMU0V9CmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShSbWlzYykKdGlsdF90aGVtZSA8LSB0aGVtZShheGlzLnRleHQueD1lbGVtZW50X3RleHQoYW5nbGU9NDUsIGhqdXN0PTEpKQpwMSA8LSBnZ3Bsb3QoZGF0YSA9IGxhc3RfMTBfdGFsa3MsIGFlcyhtYWluX3NwZWFrZXIsIHZpZXdzKSkgKwogICAgICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKwogICAgICBnZW9tX3RleHQoYWVzKGxhYmVsPXZpZXdzKSwgdmp1c3Q9MS42LCBjb2xvcj0id2hpdGUiLCBzaXplPTMpICsKICAgICAgdGlsdF90aGVtZQpwMiA8LSBnZ3Bsb3QoZGF0YSA9IHRvcF8xMF90YWxrcywgYWVzKG1haW5fc3BlYWtlciwgdmlld3MpKSArCiAgICAgIGdlb21fYmFyKHBvc2l0aW9uID0gImRvZGdlIiwgc3RhdCA9ICJpZGVudGl0eSIpICsKICAgICAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IHZpZXdzKSwgdmp1c3QgPSAxLjYsIGNvbG9yID0gIndoaXRlIiwgc2l6ZSA9IDMpICsKICAgICAgdGlsdF90aGVtZQptdWx0aXBsb3QocDEsIHAyLCBjb2xzPTIpCmBgYAoKRGlzdHJpYnV0aW9uIG9mIFZpZXdzCgpgYGB7cn0KdGVkX3NtYWxsIDwtIHN1YnNldCh0ZWQsIHZpZXdzIDwgMC40ZTcpCnAzIDwtIGdncGxvdCh0ZWQsIGFlcyh4PXZpZXdzKSkgKyAKIGdlb21faGlzdG9ncmFtKGFlcyh5PS4uZGVuc2l0eS4uKSwgY29sb3VyPSJibGFjayIsIGZpbGw9IndoaXRlIikrCiBnZW9tX2RlbnNpdHkoYWxwaGE9LjIsIGZpbGw9IiNGRjY2NjYiKQpwNCA8LSBnZ3Bsb3QodGVkX3NtYWxsLCBhZXMoeD12aWV3cykpICsKICBnZW9tX2hpc3RvZ3JhbShhZXMoeT0uLmRlbnNpdHkuLiksIGNvbG91cj0iYmxhY2siLCBmaWxsPSJ3aGl0ZSIpKwogIGdlb21fZGVuc2l0eShhbHBoYT0uMiwgZmlsbD0iI0ZGNjY2NiIpCm11bHRpcGxvdChwMywgcDQsIGNvbHM9MikKYGBgCgpgYGB7cn0KbGlicmFyeShIbWlzYykKZGVzY3JpYmUodGVkJHZpZXdzKQpgYGAKClRoZSBhdmVyYWdlIG51bWJlciBvZiB2aWV3cyBvbiBURUQgVGFsa3MgaW4gMS42IG1pbGxpb24uIGFuZCB0aGUgbWVkaWFuIG51bWJlciBvZiB2aWV3cyBpcyAxLjEyIG1pbGxpb24uIFRoaXMgc3VnZ2VzdHMgYSB2ZXJ5IGhpZ2ggYXZlcmFnZSBsZXZlbCBvZiBwb3B1bGFyaXR5IG9mIFRFRCBUYWxrcy4gV2UgYWxzbyBub3RpY2UgdGhhdCB0aGUgbWFqb3JpdHkgb2YgdGFsa3MgaGF2ZSB2aWV3cyBsZXNzIHRoYW4gNCBtaWxsaW9uLiAKCkNvbW1lbnRzCkxldCdzIGFuYWx5emUgY29tbWVudHMgb24gdGhlIHRhbGtzCmBgYHtyfQpkZXNjcmliZSh0ZWQkY29tbWVudHMpCnNkKHRlZCRjb21tZW50cykKYGBgCgpPYnNlcnZhdGlvbnMKLSBPbiBhdmVyYWdlLCB0aGVyZSBhcmUgMTkxLjUgY29tbWVudHMgb24gZXZlcnkgVEVEIFRhbGsuIEFzc3VtaW5nIHRoZSBjb21tZW50cyBhcmUgY29uc3RydWN0aXZlIGNyaXRpY2lzbSwgd2UgY2FuIGNvbmNsdWRlIHRoYXQgdGhlIFRFRCBPbmxpbmUgQ29tbXVuaXR5IGlzIGhpZ2hseSBpbnZvbHZlZCBpbiBkaXNjdXNzaW9ucyByZXZvbHZpbmcgVEVEIFRhbGtzLgotIFRoZXJlIGlzIGEgaHVnZSBzdGFuZGFyZCBkZXZpYXRpb24gYXNzb2NpYXRlZCB3aXRoIHRoZSBjb21tZW50cy4gSW4gZmFjdCwgaXQgaXMgZXZlbiBsYXJnZXIgdGhhbiB0aGUgbWVhbiBzdWdnZXN0aW5nIHRoYXQgdGhlIG1lYXN1cmVzIG1heSBiZSBzZW5zaXRpdmUgdG8gb3V0bGllcnMuIFdlIHNoYWxsIHBsb3QgdGhpcyB0byBjaGVjayB0aGUgbmF0dXJlIG9mIHRoZSBkaXN0cmlidXRpb24uCi0gVGhlIG1pbmltdW0gbnVtYmVyIG9mIGNvbW1lbnRzIG9uIGEgdGFsayBpcyAyIGFuZCB0aGUgbWF4aW11bSBpcyA2NDA0LiBUaGUgcmFuZ2UgaXMgNjQwMi4uIFRoZSBtaW5pbXVtIG51bWJlciwgdGhvdWdoLCBtYXkgYmUgYXMgYSByZXN1bHQgb2YgdGhlIHRhbGsgYmVpbmcgcG9zdGVkIGV4dHJlbWVseSByZWNlbnRseS4KCmBgYHtyfQp0ZWRfc21hbGwgPC0gc3Vic2V0KHRlZCwgY29tbWVudHMgPCA1MDApCnA1IDwtIGdncGxvdCh0ZWQsIGFlcyh4PWNvbW1lbnRzKSkgKyAKIGdlb21faGlzdG9ncmFtKGFlcyh5PS4uZGVuc2l0eS4uKSwgY29sb3VyPSJibGFjayIsIGZpbGw9IndoaXRlIikrCiBnZW9tX2RlbnNpdHkoYWxwaGE9LjIsIGZpbGw9IiNGRjY2NjYiKQpwNiA8LSBnZ3Bsb3QodGVkX3NtYWxsLCBhZXMoeD1jb21tZW50cykpICsKICBnZW9tX2hpc3RvZ3JhbShhZXMoeT0uLmRlbnNpdHkuLiksIGNvbG91cj0iYmxhY2siLCBmaWxsPSJ3aGl0ZSIpKwogIGdlb21fZGVuc2l0eShhbHBoYT0uMiwgZmlsbD0iI0ZGNjY2NiIpCm11bHRpcGxvdChwNSwgcDYsIGNvbHM9MikKYGBgCgpGcm9tIHRoZSBwbG90IGFib3ZlLCB3ZSBjYW4gc2VlIHRoYXQgdGhlIGJ1bGsgb2YgdGhlIHRhbGtzIGhhdmUgZmV3ZXIgdGhhbiA1MDAgY29tbWVudHMuIFRoaXMgY2xlYXJseSBzdWdnZXN0cyB0aGF0IHRoZSBtZWFuIG9idGFpbmVkIGFib3ZlIGhhcyBiZWVuIGhlYXZpbHkgaW5mbHVlbmNlZCBieSBvdXRsaWVycy4gVGhpcyBpcyBwb3NzaWJsZSBiZWNhdXNlIHRoZSBudW1iZXIgb2Ygc2FtcGxlcyBpcyBvbmx5IDI1NTAgdGFsa3MuCgpBbm90aGVyIHF1ZXN0aW9uIHRoYXQgSSBhbSBpbnRlcmVzdGVkIGluIGlzIGlmIHRoZSBudW1iZXIgb2Ygdmlld3MgaXMgY29ycmVsYXRlZCB3aXRoIHRoZSBudW1iZXIgb2YgY29tbWVudHMuIFdlIHNob3VsZCB0aGluayB0aGF0IHRoaXMgaXMgdGhlIGNhc2UgYXMgbW9yZSBwb3B1bGFyIHZpZGVvcyB0ZW5kIHRvIGhhdmUgbW9yZSBjb21tZW50cy4gTGV0IHVzIGZpbmQgb3V0LgoKYGBge3J9CnNjYXR0ZXIxIDwtIHFwbG90KHZpZXdzLGNvbW1lbnRzLCBkYXRhPXRlZCkgICsgCiAgICAgICAgIHNjYWxlX3hfY29udGludW91cyhsaW1pdHM9YyhtaW4odGVkJHZpZXdzKSxtYXgodGVkJHZpZXdzKSkpICsgCiAgICAgICAgIHNjYWxlX3lfY29udGludW91cyhsaW1pdHM9YyhtaW4odGVkJGNvbW1lbnRzKSxtYXgodGVkJGNvbW1lbnRzKSkpICsgCiAgICAgICAgIGdlb21fcnVnKGNvbD1yZ2IoLjUsMCwwLGFscGhhPS4yKSkKc2NhdHRlcjEKYGBgCgpgYGB7cn0KdmNfY29yIDwtIGNvcih0ZWQkdmlld3MsIHRlZCRjb21tZW50cykKcHJpbnQoIkNvcnJlbGF0aW9uIGJldHdlZW4gVmlld3MgYW5kIENvbW1lbnRzIikKdmNfY29yCmBgYAoKQXMgdGhlIHNjYXR0ZXJwbG90IGFuZCB0aGUgY29ycmVsYXRpb24gbWF0cml4IHNob3csIHRoZSBwZWFyc29uIGNvZWZmaWNpZW50IGlzIHNsaWdodGx5IG1vcmUgdGhhbiAwLjUuIFRoaXMgc3VnZ2VzdHMgYSBtZWRpdW0gdG8gc3Ryb25nIGNvcnJlbGF0aW9uIGJldHdlZW4gdGhlIHR3byBxdWFudGl0aWVzLiBUaGlzIHJlc3VsdCB3YXMgcHJldHR5IGV4cGVjdGVkIGFzIG1lbnRpb25lZCBhYm92ZS4gTGV0IHVzIG5vdyBjaGVjayB0aGUgbnVtYmVyIG9mIHZpZXdzIGFuZCBjb21tZW50cyBvbiB0aGUgMTAgbW9zdCBjb21tZW50ZWQgVEVEIFRhbGtzIG9mIGFsbCB0aW1lLgoKYGBge3J9CnRlbl90YWxrcyA8LSBhcnJhbmdlKHRlZCwgY29tbWVudHMpCmtlZXBzIDwtIGMoInRpdGxlIiwgIm1haW5fc3BlYWtlciIsICJ2aWV3cyIsICJjb21tZW50cyIpCnRlbl90YWxrcyA8LSBzdWJzZXQodGVuX3RhbGtzLCBzZWxlY3QgPSBrZWVwcykKCmxhc3RfMTBfdGFsa3MgPC0gdGVuX3RhbGtzWzA6MTAsXQpsYXN0XzEwX3RhbGtzCgp0ZW5fdGFsa3MgPC0gYXJyYW5nZSh0ZWQsIGRlc2MoY29tbWVudHMpKQp0ZW5fdGFsa3MgPC0gc3Vic2V0KHRlbl90YWxrcywgc2VsZWN0ID0ga2VlcHMpCnRvcF8xMF90YWxrcyA8LSB0ZW5fdGFsa3NbMDoxMCxdCnRvcF8xMF90YWxrcwpgYGAKCmBgYHtyIGZpZy53aWR0aD03LCBmaWcuaGVpZ2h0PTQsIGVjaG89RkFMU0V9Cgp0aWx0X3RoZW1lIDwtIHRoZW1lKGF4aXMudGV4dC54PWVsZW1lbnRfdGV4dChhbmdsZT00NSwgaGp1c3Q9MSkpCnA3IDwtIGdncGxvdChkYXRhID0gbGFzdF8xMF90YWxrcywgYWVzKG1haW5fc3BlYWtlciwgY29tbWVudHMpKSArCiAgICAgIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKSArCiAgICAgIGdlb21fdGV4dChhZXMobGFiZWw9Y29tbWVudHMpLCB2anVzdD0xLjYsIGNvbG9yPSJ3aGl0ZSIsIHNpemU9MykgKwogICAgICB0aWx0X3RoZW1lCnA4IDwtIGdncGxvdChkYXRhID0gdG9wXzEwX3RhbGtzLCBhZXMobWFpbl9zcGVha2VyLCBjb21tZW50cykpICsKICAgICAgZ2VvbV9iYXIocG9zaXRpb24gPSAiZG9kZ2UiLCBzdGF0ID0gImlkZW50aXR5IikgKwogICAgICBnZW9tX3RleHQoYWVzKGxhYmVsID0gY29tbWVudHMpLCB2anVzdCA9IDEuNiwgY29sb3IgPSAid2hpdGUiLCBzaXplID0gMykgKwogICAgICB0aWx0X3RoZW1lCm11bHRpcGxvdChwNywgcDgsIGNvbHM9MikKCmBgYAoKQXMgY2FuIGJlIHNlZW4gYWJvdmUsIFJpY2hhcmQgRGF3a2lucycgdGFsayBvbiBNaWxpdGFudCBBdGhlaXNtJyBnZW5lcmF0ZWQgdGhlIGdyZWF0ZXN0IGFtb3VudCBvZiBkaXNjdXNzaW9uIGFuZCBvcGluaW9ucyBkZXNwaXRlIGhhdmluZyBzaWduaWZpY2FudGx5IGxlc3NlciB2aWV3cyB0aGFuIEtlbiBSb2JpbnNvbidzIHRhbGssIHdoaWNoIGlzIHNlY29uZCBpbiB0aGUgbGlzdC4gVGhpcyByYWlzZXMgc29tZSBpbnRlcmVzdGluZyBxdWVzdGlvbnMuCgpXaGljaCB0YWxrcyB0ZW5kIHRvIGF0dHJhY3QgdGhlIGxhcmdlc3QgYW1vdW50IG9mIGRpc2N1c3Npb24/CgpUbyBhbnN3ZXIgdGhpcyBxdWVzdGlvbiwgd2Ugd2lsbCBkZWZpbmUgYSBuZXcgZmVhdHVyZSBkaXNjdXNzaW9uIHF1b3RpZW50IHdoaWNoIGlzIHNpbXBseSB0aGUgcmF0aW8gb2YgdGhlIG51bWJlciBvZiBjb21tZW50cyB0byB0aGUgbnVtYmVyIG9mIHZpZXdzLiBXZSB3aWxsIHRoZW4gY2hlY2sgd2hpY2ggdGFsa3MgaGF2ZSB0aGUgbGFyZ2VzdCBkaXNjdXNzaW9uIHF1b3RpZW50LgoKYGBge3J9CnRlZCRkaXNfcXVvIDwtIHRlZCRjb21tZW50cy90ZWQkdmlld3MKdGVuX3RhbGtzIDwtIGFycmFuZ2UodGVkLCBkaXNfcXVvKQprZWVwcyA8LSBjKCJ0aXRsZSIsICJtYWluX3NwZWFrZXIiLCAidmlld3MiLCAiY29tbWVudHMiLCAiZGlzX3F1byIpCnRlbl90YWxrcyA8LSBzdWJzZXQodGVuX3RhbGtzLCBzZWxlY3QgPSBrZWVwcykKCmxhc3RfMTBfdGFsa3MgPC0gdGVuX3RhbGtzWzA6MTAsXQpsYXN0XzEwX3RhbGtzCgp0ZW5fdGFsa3MgPC0gYXJyYW5nZSh0ZWQsIGRlc2MoZGlzX3F1bykpCnRlbl90YWxrcyA8LSBzdWJzZXQodGVuX3RhbGtzLCBzZWxlY3QgPSBrZWVwcykKdG9wXzEwX3RhbGtzIDwtIHRlbl90YWxrc1swOjEwLF0KdG9wXzEwX3RhbGtzCmBgYAoKVGhpcyBhbmFseXNpcyBoYXMgYWN0dWFsbHkgcmFpc2VkIGV4dHJlbWVseSBpbnRlcmVzdGluZyBpbnNpZ2h0cy4gSGFsZiBvZiB0aGUgdGFsa3MgaW4gdGhlIHRvcCAxMCBhcmUgb24gdGhlIGxpbmVzIG9mIEZhaXRoIGFuZCBSZWxpZ2lvbi4gSSBzdXNwZWN0IHNjaWVuY2UgYW5kIHJlbGlnaW9uIGlzIHN0aWxsIGEgdmVyeSBob3RseSBkZWJhdGVkIHRvcGljIGV2ZW4gaW4gdGhlIDIxc3QgY2VudHVyeS4gV2Ugc2hhbGwgY29tZSBiYWNrIHRvIHRoaXMgaHlwb3RoZXNpcyBpbiBhIGxhdGVyIHNlY3Rpb24uCgpUaGUgbW9zdCBkaXNjdXNzZXMgdGFsaywgdGhvdWdoLCBpcyBUaGUgQ2FzZSBmb3IgU2FtZSBTZXggTWFycmlhZ2UgKHdoaWNoIGhhcyByZWxpZ2lvdXMgdW5kZXJ0b25lcykuIFRoaXMgaXMgbm90IHRoYXQgc3VycHJpc2luZyBjb25zaWRlcmluZyB0aGUgYW1vdW50IG9mIGRlYmF0ZSB0aGUgdG9waWMgY2F1c2VkIGJhY2sgaW4gMjAwOSAodGhlIHRpbWUgdGhlIHRhbGsgd2FzIGZpbG1lZCkuCgojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKCkFuYWx5emluZyBURUQgdGFsa3MgYnkgdGhlIG1vbnRoIGFuZCB0aGUgeWVhcgoKVEVEIChlc3BlY2lhbGx5IFRFRHgpIFRhbGtzIHRlbmQgdG8gb2NjdXIgYWxsIHRocm91Z2hvdXQgdGhlIHllYXIuIElzIHRoZXJlIGEgaG90IG1vbnRoIGFzIGZhciBhcyBURUQgaXMgY29uY2VybmVkPyBJbiBvdGhlciB3b3JkcywgaG93IGFyZSB0aGUgdGFsa3MgZGlzdHJpYnV0ZWQgdGhyb3VnaG91dCB0aGUgbW9udGhzIHNpbmNlIGl0cyBpbmNlcHRpb24/IExldCB1cyBmaW5kIG91dC4KCmBgYHtyfQp0ZWQkZmlsbWluZ19tb250aCA8LSBhcy5udW1lcmljKGZvcm1hdCh0ZWQkZmlsbV9kYXRlLCBmb3JtYXQ9ICIlbSIpKQp0ZWQkZmlsbWluZ195ZWFyIDwtIGFzLm51bWVyaWMoZm9ybWF0KHRlZCRmaWxtX2RhdGUsIGZvcm1hdCA9ICIlWSIpKQptb250aF9kZiA8LSBhcy5kYXRhLmZyYW1lKHRhYmxlKHRlZCRmaWxtaW5nX21vbnRoKSkKY29sbmFtZXMobW9udGhfZGYpIDwtIGMoIk1vbnRoIiwgIlRhbGtzIikKbW9udGhfZGYkTW9udGggPC0gYygiSmFuIiwgIkZlYiIsICJNYXIiLCAiQXByIiwgIk1heSIsICJKdW4iLCAiSnVsIiwgIkF1ZyIsICJTZXAiLCAiT2N0IiwgIk5vdiIsICJEZWMiKQojVHVybiB5b3VyICdNb250aCcgY29sdW1uIGludG8gYSBjaGFyYWN0ZXIgdmVjdG9yCm1vbnRoX2RmJE1vbnRoIDwtIGFzLmNoYXJhY3Rlcihtb250aF9kZiRNb250aCkKI1RoZW4gdHVybiBpdCBiYWNrIGludG8gYW4gb3JkZXJlZCBmYWN0b3IKbW9udGhfZGYkTW9udGggPC0gZmFjdG9yKG1vbnRoX2RmJE1vbnRoLCBsZXZlbHM9dW5pcXVlKG1vbnRoX2RmJE1vbnRoKSkKcDggPC0gZ2dwbG90KGRhdGEgPSBtb250aF9kZiwgYWVzKE1vbnRoLCBUYWxrcykpICsKICAgICAgZ2VvbV9iYXIocG9zaXRpb24gPSAiZG9kZ2UiLCBzdGF0ID0gImlkZW50aXR5IiwgY29sb3IgPSAiYmx1ZSIsIGZpbGw9ImJsdWUiKSArCiAgICAgIGdlb21fdGV4dChhZXMobGFiZWwgPSBUYWxrcyksIHZqdXN0ID0gMS42LCBjb2xvciA9ICJ3aGl0ZSIsIHNpemUgPSAzKSArCiAgICAgIHRpbHRfdGhlbWUKcDgKCmBgYAoKRmVicnVhcnkgaXMgY2xlYXJseSB0aGUgbW9zdCBwb3B1bGFyIG1vbnRoIGZvciBURUQgQ29uZmVyZW5jZXMgd2hlcmVhcyBBdWd1c3QgYW5kIEphbnVhcnkgYXJlIHRoZSBsZWFzdCBwb3B1bGFyLiBGZWJydWFyeSdzIHBvcHVsYXJpdHkgaXMgbGFyZ2VseSBkdWUgdG8gdGhlIGZhY3QgdGhhdCB0aGUgb2ZmaWNpYWwgVEVEIENvbmZlcmVuY2VzIGFyZSBoZWxkIGluIEZlYnJ1YXJ5LiBMZXQgdXMgY2hlY2sgdGhlIGRpc3RyaWJ1dGlvbiBmb3IgVEVEeCB0YWxrcyBvbmx5LgoKYGBge3J9CnRlZHggPC0gZmlsdGVyKHRlZCwgZ3JlcGwoIlRFRHgiLCB0ZWQkZXZlbnQsIGZpeGVkID0gVFJVRSkpCm1vbnRoX2RmIDwtIGFzLmRhdGEuZnJhbWUodGFibGUodGVkeCRmaWxtaW5nX21vbnRoKSkKY29sbmFtZXMobW9udGhfZGYpIDwtIGMoIk1vbnRoIiwgIlRhbGtzIikKbW9udGhfZGYkTW9udGggPC0gYygiSmFuIiwgIkZlYiIsICJNYXIiLCAiQXByIiwgIk1heSIsICJKdW4iLCAiSnVsIiwgIkF1ZyIsICJTZXAiLCAiT2N0IiwgIk5vdiIsICJEZWMiKQojVHVybiB5b3VyICdNb250aCcgY29sdW1uIGludG8gYSBjaGFyYWN0ZXIgdmVjdG9yCm1vbnRoX2RmJE1vbnRoIDwtIGFzLmNoYXJhY3Rlcihtb250aF9kZiRNb250aCkKI1RoZW4gdHVybiBpdCBiYWNrIGludG8gYW4gb3JkZXJlZCBmYWN0b3IKbW9udGhfZGYkTW9udGggPC0gZmFjdG9yKG1vbnRoX2RmJE1vbnRoLCBsZXZlbHM9dW5pcXVlKG1vbnRoX2RmJE1vbnRoKSkKcDkgPC0gZ2dwbG90KGRhdGEgPSBtb250aF9kZiwgYWVzKE1vbnRoLCBUYWxrcykpICsKICAgICAgZ2VvbV9iYXIocG9zaXRpb24gPSAiZG9kZ2UiLCBzdGF0ID0gImlkZW50aXR5IiwgY29sb3IgPSAicmVkIiwgZmlsbD0icmVkIikgKwogICAgICBnZW9tX3RleHQoYWVzKGxhYmVsID0gVGFsa3MpLCB2anVzdCA9IDEuNiwgY29sb3IgPSAid2hpdGUiLCBzaXplID0gMykgKwogICAgICB0aWx0X3RoZW1lCnA5CmBgYAoKQXMgZmFyIGFzIFRFRHggdGFsa3MgYXJlIGNvbmNlcm5lZCwgTm92ZW1iZXIgaXMgdGhlIG1vc3QgcG9wdWxhciBtb250aC4gSG93ZXZlciwgd2UgY2Fubm90IHRha2UgdGhpcyByZXN1bHQgYXQgZmFjZSB2YWx1ZSBhcyB2ZXJ5IGZldyBvZiB0aGUgVEVEeCB0YWxrcyBhcmUgYWN0dWFsbHkgdXBsb2FkZWQgdG8gdGhlIFRFRCB3ZWJzaXRlIGFuZCB0aGVyZWZvcmUsIGl0IGlzIGVudGlyZWx5IHBvc3NpYmxlIHRoYXQgdGhlIHNhbXBsZSBpbiBvdXIgZGF0YXNldCBpcyBub3QgYXQgYWxsIHJlcHJlc2VudGF0aXZlIG9mIGFsbCBURUR4IHRhbGtzLiBBIHNsaWdodGx5IG1vcmUgYWNjdXJhdGUgc3RhdGVtZW50IHdvdWxkIGJlIHRoYXQgdGhlIG1vc3QgcG9wdWxhciBURUR4IHRhbGtzIHRha2UgcGxhY2UgdGhlIG1vc3QgaW4gT2N0b2JlciBhbmQgTm92ZW1iZXIuCgpUaGUgbmV4dCBxdWVzdGlvbiBJJ20gaW50ZXJlc3RlZCBpbiBpcyB0aGUgbW9zdCBwb3B1bGFyIGRheXMgZm9yIGNvbmR1Y3RpbmcgVEVEIGFuZCBURUR4IGNvbmZlcmVuY2VzLiBUaGUgdG9vbHMgYXBwbGllZCBhcmUgdmVyeSBzZW5zaWJsZSB0byB0aGUgcHJvY2VkdXJlIGFwcGxpZWQgZm9yIG1vbnRocy4KCmBgYHtyfQp0ZWQkZmlsbV93ZWVrZGF5IDwtIHdlZWtkYXlzKGFzLkRhdGUodGVkJGZpbG1fZGF0ZSkpCndlZWtkYXlfZGYgPC0gYXMuZGF0YS5mcmFtZSh0YWJsZSh0ZWQkZmlsbV93ZWVrZGF5KSkKCndlZWtkYXlfZGYKCmNvbG5hbWVzKHdlZWtkYXlfZGYpIDwtIGMoIldlZWtkYXkiLCAiVGFsa3MiKQp3ZWVrZGF5X2RmIDwtIHdlZWtkYXlfZGZbYyg0LDIsNiw3LDUsMSwzKSxdCiNUdXJuIHlvdXIgJ01vbnRoJyBjb2x1bW4gaW50byBhIGNoYXJhY3RlciB2ZWN0b3IKd2Vla2RheV9kZiRXZWVrZGF5IDwtIGFzLmNoYXJhY3Rlcih3ZWVrZGF5X2RmJFdlZWtkYXkpCiNUaGVuIHR1cm4gaXQgYmFjayBpbnRvIGFuIG9yZGVyZWQgZmFjdG9yCndlZWtkYXlfZGYkV2Vla2RheSA8LSBmYWN0b3Iod2Vla2RheV9kZiRXZWVrZGF5LCBsZXZlbHM9dW5pcXVlKHdlZWtkYXlfZGYkV2Vla2RheSkpCnAxMCA8LSBnZ3Bsb3QoZGF0YSA9IHdlZWtkYXlfZGYsIGFlcyhmYWN0b3IoV2Vla2RheSksIFRhbGtzKSkgKwogICAgICBnZW9tX2Jhcihwb3NpdGlvbiA9ICJkb2RnZSIsIHN0YXQgPSAiaWRlbnRpdHkiLCBjb2xvciA9ICJncmVlbiIsIGZpbGw9ImdyZWVuIikgKwogICAgICBnZW9tX3RleHQoYWVzKGxhYmVsID0gVGFsa3MpLCB2anVzdCA9IDEuNiwgY29sb3IgPSAiYmxhY2siLCBzaXplID0gMykgKwogICAgICB0aWx0X3RoZW1lCnAxMApgYGAKClRoZSBkaXN0cmlidXRpb24gb2YgZGF5cyBpcyBhbG1vc3QgYSBiZWxsIGN1cnZlIHdpdGggV2VkbmVzZGF5IGFuZCBUaHVyc2RheSBiZWluZyB0aGUgbW9zdCBwb3B1bGFyIGRheXMgYW5kIFN1bmRheSBiZWluZyB0aGUgbGVhc3QgcG9wdWxhci4gVGhpcyBpcyBwcmV0dHkgaW50ZXJlc3RpbmcgYmVjYXVzZSBJIHdhcyBvZiB0aGUgb3BpbmlvbiB0aGF0IG1vc3QgVEVEIENvbmZlcmVuY2VzIHdvdWxkIGhhcHBlbiBzb21ldGltZSBpbiB0aGUgd2Vla2VuZC4KCkxldCB1cyBub3cgdmlzdWFsaXplIHRoZSBudW1iZXIgb2YgVEVEIHRhbGtzIHRocm91Z2ggdGhlIHllYXJzIGFuZCBjaGVjayBpZiBvdXIgaHVuY2ggdGhhdCB0aGV5IGhhdmUgZ3Jvd24gc2lnbmlmaWNhbnRseSBpcyBpbmRlZWQgdHJ1ZS4KCmBgYHtyfQp5ZWFyX2RmIDwtIGFzLmRhdGEuZnJhbWUodGFibGUodGVkJGZpbG1pbmdfeWVhcikpCnllYXJfZGYKY29sbmFtZXMoeWVhcl9kZikgPC0gYygiWWVhciIsICJUYWxrcyIpCiNUdXJuIHlvdXIgJ01vbnRoJyBjb2x1bW4gaW50byBhIGNoYXJhY3RlciB2ZWN0b3IKI21vbnRoX2RmJE1vbnRoIDwtIGFzLmNoYXJhY3Rlcihtb250aF9kZiRNb250aCkKI1RoZW4gdHVybiBpdCBiYWNrIGludG8gYW4gb3JkZXJlZCBmYWN0b3IKI21vbnRoX2RmJE1vbnRoIDwtIGZhY3Rvcihtb250aF9kZiRNb250aCwgbGV2ZWxzPXVuaXF1ZShtb250aF9kZiRNb250aCkpCnAxMSA8LSBnZ3Bsb3QoZGF0YSA9IHllYXJfZGYsIGFlcyhZZWFyLCBUYWxrcywgZ3JvdXAgPSAxKSkgKwogICAgICBnZW9tX2xpbmUoY29sb3IgPSAiYmx1ZSIpICsKICAgICAgZ2VvbV9wb2ludCgpICsKICAgICAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IFRhbGtzKSwgdmp1c3QgPSAxLjYsIGNvbG9yID0gImJsYWNrIiwgc2l6ZSA9IDMpICsKICAgICAgdGlsdF90aGVtZQpwMTEKYGBgCgpPYmVydmF0aW9ucwotIEFzIGV4cGVjdGVkLCB0aGUgbnVtYmVyIG9mIFRFRCBUYWxrcyBoYXZlIGdyYWR1YWxseSBpbmNyZWFzZWQgb3ZlciB0aGUgeWVhcnMgc2luY2UgaXRzIGluY2VwdGlvbiBpbiAxOTg0LgotIFRoZXJlIHdhcyBhIHNoYXJwIGluY3JlYXNlIGluIHRoZSBudW1iZXIgaWYgdGFsa3MgaW4gMjAwOS4gSXQgbWlnaHQgYmUgaW50ZXJlc3RpbmcgdG8ga25vdyB0aGUgcmVhc29ucyBiZWhpbmQgMjAwOSBiZWluZyB0aGUgdGlwcGluZyBwb2ludCB3aGVyZSB0aGUgbnVtYmVyIG9mIHRhbGtzIGluY3JlYXNlZCBtb3JlIHRoYW4gdHdvZm9sZC4KLSBUaGUgbnVtYmVyIG9mIHRhbGtzIGhhdmUgYmVlbiBwcmV0dHkgbXVjaCBjb25zdGFudCBzaW5jZSAyMDA5LgoKRmluYWxseSwgdG8gcHV0IGl0IGFsbCB0b2dldGhlciwgbGV0IHVzIGNvbnN0cnVjdCBhIGhlYXQgbWFwIHRoYXQgc2hvd3MgdXMgdGhlIG51bWJlciBvZiB0YWxrcyBieSBtb250aCBhbmQgeWVhci4gVGhpcyB3aWxsIGdpdmUgdXMgYSBnb29kIHN1bW1hcnkgb2YgdGhlIGRpc3RyaWJ1dGlvbiBvZiB0YWxrcy4KCmBgYHtyfQoKa2VlcHMgPC0gYygiZmlsbWluZ19tb250aCIsICJmaWxtaW5nX3llYXIiKQpoZWF0bWFwX2RmIDwtIHRlZCAlPiUgc3Vic2V0KHNlbGVjdCA9IGtlZXBzKSAlPiUgYXJyYW5nZShmaWxtaW5nX3llYXIpCmhlYXRtYXBfZGYgPC0gYXMuZGF0YS5mcmFtZSh0YWJsZShoZWF0bWFwX2RmKSkKaGVhdG1hcF9kZiRmaWxtaW5nX21vbnRoIDwtIG1vbnRoLmFiYltoZWF0bWFwX2RmJGZpbG1pbmdfbW9udGhdCmhlYXRtYXBfZGYkZmlsbWluZ19tb250aCA8LSBhcy5jaGFyYWN0ZXIoaGVhdG1hcF9kZiRmaWxtaW5nX21vbnRoKQoKaGVhdG1hcF9kZiRmaWxtaW5nX21vbnRoIDwtIGZhY3RvcihoZWF0bWFwX2RmJGZpbG1pbmdfbW9udGgsIGxldmVscz11bmlxdWUobW9udGhfZGYkTW9udGgpKQojaGVhdG1hcF9kZiAKCmdncGxvdChoZWF0bWFwX2RmLCBhZXMoZmlsbWluZ195ZWFyLCBmYWN0b3IoZmlsbWluZ19tb250aCkpKSArCiAgZ2VvbV90aWxlKGFlcyhmaWxsID0gRnJlcSksIGNvbG9yID0gIndoaXRlIikgKwogIGdlb21fdGV4dChhZXMoZmlsbCA9IGhlYXRtYXBfZGYkRnJlcSwgbGFiZWwgPSBoZWF0bWFwX2RmJEZyZXEpKSArCiAgc2NhbGVfZmlsbF9ncmFkaWVudDIobG93ID0gImRhcmtyZWQiLCAKICAgICAgICAgICAgICAgICAgICAgICBtaWQgPSAid2hpdGUiLCAKICAgICAgICAgICAgICAgICAgICAgICBoaWdoID0gIm1pZG5pZ2h0Ymx1ZSIsIAogICAgICAgICAgICAgICAgICAgICAgIG1pZHBvaW50ID0gcm91bmQobWVhbihoZWF0bWFwX2RmJEZyZXEpKSkgKwogIHlsYWIoIlllYXIiKSArCiAgeGxhYigiTW9udGhzIikgKwogIHRoZW1lKGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApLAogICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiksCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTE2KSwKICAgICAgICBheGlzLnRpdGxlPWVsZW1lbnRfdGV4dChzaXplPTE0LGZhY2U9ImJvbGQiKSwKICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBoanVzdCA9IDEpKSArCiAgbGFicyhmaWxsID0gIkZyZXEiKQoKYGBgCgojIyMjIyMKVGVkIFNwZWFrZXJzCgpJbiB0aGlzIHNlY3Rpb24sIHdlIHdpbGwgdHJ5IGFuZCBnYWluIGluc2lnaHQgYWJvdXQgYWxsIHRoZSBhbWF6aW5nIHNwZWFrZXJzIHdobyBoYXZlIG1hbmFnZWQgdG8gaW5zcGlyZSBtaWxsaW9ucyBvZiBwZW9wbGUgdGhyb3VnaCB0aGVpciB0YWxrcyBvbiB0aGUgVEVEIFBsYXRmb3JtLiBUaGUgZmlyc3QgcXVlc3Rpb24gd2Ugc2hhbGwgYXNrIGluIHRoaXMgc2VjdGlvbiBpcyB3aG8gYXJlIHRoZSBtb3N0IHBvcHVsYXIgVEVEIFNwZWFrZXJzLiBUaGF0IGlzLCB3aGljaCBzcGVha2VycyBoYXZlIGdpdmVuIHRoZSBtb3N0IG51bWJlciBvZiBURUQgVGFsa3MuCgpgYGB7cn0Kc3BlYWtlcl9kZiA8LSBhcy5kYXRhLmZyYW1lKHRhYmxlKHRlZCRtYWluX3NwZWFrZXIpKQpzcGVha2VyX2RmIDwtIGFycmFuZ2Uoc3BlYWtlcl9kZiwgZGVzYyhGcmVxKSkKc3BlYWtlcl9kZgpgYGAKCkhhbnMgUm9zbGluZywgdGhlIFN3aXNzIEhlYWx0aCBQcm9mZXNzb3IgaXMgY2xlYXJseSB0aGUgbW9zdCBwb3B1bGFyIFRFRCBTcGVha2VyLCB3aXRoIG1vcmUgdGhhbiA5IGFwcGVhcmFuY2VzIG9uIHRoZSBURUQgRm9ydW0uIEp1YW4gRW5yaXF1ZXogY29tZXMgYSBjbG9zZSBzZWNvbmQgd2l0aCA3IGFwcGVhcmFuY2VzLiBSaXZlcyBhbmQgTWFyY28gVGVtcGVzdCBoYXZlIGdyYWNlZCB0aGUgVEVEIHBsYXRmb3JtIDYgdGltZXMuCgpXaGljaCBvY2N1cGF0aW9uIHNob3VsZCB5b3UgY2hvb3NlIGlmIHlvdSB3YW50IHRvIGJlY29tZSBhIFRFRCBTcGVha2VyPyBMZXQgdXMgaGF2ZSBhIGxvb2sgd2hhdCBraW5kIG9mIHBlb3BsZSBURUQgaXMgbW9zdCBpbnRlcmVzdGVkIGluIGludml0aW5nIHRvIGl0cyBldmVudHMuCgpgYGB7cn0Kb2NjdXBhdGlvbl9kZiA8LSBhcy5kYXRhLmZyYW1lKHRhYmxlKHRlZCRzcGVha2VyX29jY3VwYXRpb24pKQpvY2N1cGF0aW9uX2RmIDwtIGFycmFuZ2Uob2NjdXBhdGlvbl9kZiwgZGVzYyhGcmVxKSkKb2NjdXBhdGlvbl9kZiA8LSBoZWFkKG9jY3VwYXRpb25fZGYsIDEwKQpjb2xuYW1lcyhvY2N1cGF0aW9uX2RmKSA8LSBjKCJPY2N1cGF0aW9uIiwgIkFwcGVhcmFuY2VzIikKb2NjdXBhdGlvbl9kZiRPY2N1cGF0aW9uIDwtIGFzLmNoYXJhY3RlcihvY2N1cGF0aW9uX2RmJE9jY3VwYXRpb24pCm9jY3VwYXRpb25fZGYkT2NjdXBhdGlvbiA8LSBmYWN0b3Iob2NjdXBhdGlvbl9kZiRPY2N1cGF0aW9uLCBsZXZlbHM9b2NjdXBhdGlvbl9kZiRPY2N1cGF0aW9uKQpwMTIgPC0gZ2dwbG90KGRhdGEgPSBvY2N1cGF0aW9uX2RmLCBhZXMoZmFjdG9yKE9jY3VwYXRpb24pLCBBcHBlYXJhbmNlcykpICsKICAgICAgZ2VvbV9iYXIocG9zaXRpb24gPSAiZG9kZ2UiLCBzdGF0ID0gImlkZW50aXR5IiwgY29sb3IgPSAiY3lhbiIsIGZpbGw9ImN5YW4iKSArCiAgICAgIGdlb21fdGV4dChhZXMobGFiZWwgPSBBcHBlYXJhbmNlcyksIHZqdXN0ID0gMS42LCBjb2xvciA9ICJibGFjayIsIHNpemUgPSAzKSArCiAgICAgIHRpbHRfdGhlbWUKcDEyCmBgYAoKT2JzZXJ2YXRpb25zCi0gV3JpdGVycyBhcmUgdGhlIG1vc3QgcG9wdWxhciB3aXRoIG1vcmUgdGhhbiA0NSBzcGVha2VycyBpZGVudGlmeWluZyB0aGVtc2VsdmVzIGFzIHRoZSBhZm9yZW1lbnRpb25lZC4KLSBBcnRpc3RzIGFuZCBEZXNpZ25lcnMgY29tZSBhIGRpc3RhbnQgc2Vjb25kIHdpdGggYXJvdW5kIDM1IHNwZWFrZXJzIGluIGVhY2ggY2F0ZWdvcnkuCi0gVGhpcyByZXN1bHQgbXVzdCBiZSB0YWtlbiB3aXRoIGEgcGluY2ggb2Ygc2FsdCBhcyBhIGNvbnNpZGVyYWJsZSBudW1iZXIgb2Ygc3BlYWtlcnMgaWRlbnRpZnkgdGhlbXNlbHZlcyB3aXRoIG11bHRpcGxlIHByb2Zlc3Npb25zIChmb3IgZXhhbXBsZSwgd3JpdGVyL2VudHJlcHJlbmV1cikuIAoKRG8gc29tZSBwcm9mZXNzaW9ucyB0ZW5kIHRvIGF0dHJhY3QgYSBsYXJnZXIgbnVtYmVyIG9mIHZpZXdlcnM/IERvIGFuc3dlciB0aGlzIHF1ZXN0aW9uIGxldCB1cyB2aXN1YWxpc2UgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHRoZSB0b3AgMTAgbW9zdCBwb3B1bGFyIHByb2Zlc3Npb25zIGFuZCB0aGUgdmlld3MgdGhhdCBnYXJuZXJlZCBpbiB0aGUgZm9ybSBvZiBhIGJveCBwbG90LgoKCmBgYHtyfQp0b3Bfb2NjdXBhdGlvbl92aWV3cyA8LSBmaWx0ZXIodGVkLCB0ZWQkc3BlYWtlcl9vY2N1cGF0aW9uICVpbiUgb2NjdXBhdGlvbl9kZiRPY2N1cGF0aW9uKQpwMTMgPC0gZ2dwbG90KHRvcF9vY2N1cGF0aW9uX3ZpZXdzLCBhZXMoeD1zcGVha2VyX29jY3VwYXRpb24sIHk9dmlld3MpKSArIAogIGdlb21fYm94cGxvdCgpICsKICBnZW9tX2ppdHRlcihzaGFwZT0xNiwgcG9zaXRpb249cG9zaXRpb25faml0dGVyKDAuMikpICsKICB0aWx0X3RoZW1lCnAxMyAKYGBgCgpPbiBhdmVyYWdlLCBvdXQgb2YgdGhlIHRvcCAxMCBtb3N0IHBvcHVsYXIgcHJvZmVzc2lvbnMsIFBzeWNob2xvZ2lzdHMgdGVuZCB0byBnYXJuZXIgdGhlIG1vc3Qgdmlld3MuIFdyaXRlcnMgaGF2ZSB0aGUgZ3JlYXRlc3QgcmFuZ2Ugb2Ygdmlld3MgYmV0d2VlbiB0aGUgZmlyc3QgYW5kIHRoZSB0aGlyZCBxdWFydGlsZS4uCgpGaW5hbGx5LCBsZXQgdXMgY2hlY2sgdGhlIG51bWJlciBvZiB0YWxrcyB3aGljaCBoYXZlIGhhZCBtb3JlIHRoYW4gb25lIHNwZWFrZXIuCgpgYGB7cn0Kc3BlYWtlcl9jb3VudCA8LSB0YWJsZSh0ZWQkbnVtX3NwZWFrZXIpCnNwZWFrZXJfY291bnQKYGBgCgpBbG1vc3QgZXZlcnkgdGFsayBoYXMganVzdCBvbmUgc3BlYWtlci4gVGhlcmUgYXJlIGNsb3NlIHRvIDUwIHRhbGtzIHdoZXJlIHR3byBwZW9wbGUgc2hhcmVkIHRoZSBzdGFnZS4gVGhlIG1heGltdW0gbnVtYmVyIG9mIHNwZWFrZXJzIHRvIHNoYXJlIGEgc2luZ2xlIHN0YWdlIHdhcyA1LiBJIHN1c3BlY3QgdGhpcyB3YXMgYSBkYW5jZSBwZXJmb3JtYW5jZS4gTGV0J3MgaGF2ZSBhIGxvb2suCgpgYGB7cn0KZmlsdGVyKHRlZCwgdGVkJG51bV9zcGVha2VyPT01KQpgYGAKCk15IGh1bmNoIHdhcyBjb3JyZWN0LiBJdCBpcyBhIHRhbGsgdGl0bGVkIEEgZGFuY2UgdG8gaG9ub3IgTW90aGVyIEVhcnRoIGJ5IEpvbiBCb29neiBhbmQgTGlsIEJ1Y2sgYXQgdGhlIFRFRCAyMDE3IENvbmZlcmVuY2UuCgojIyMjIyMjIyMjIyMjIyMjIwpURUQgRXZlbnRzCldoaWNoIFRFRCBFdmVudHMgdGVuZCB0byBob2xkIHRoZSBtb3N0IG51bWJlciBvZiBURUQuY29tIHVwbG9hZCB3b3J0aHkgZXZlbnRzPyBXZSB3aWxsIHRyeSB0byBhbnN3ZXIgdGhhdCBxdWVzdGlvbiBpbiB0aGlzIHNlY3Rpb24uCgoKYGBge3J9CmV2ZW50c19kZiA8LSB0ZWQgJT4lIHNlbGVjdChjKCJldmVudCIpKSAlPiUgZ3JvdXBfYnkoImV2ZW50IikKZXZlbnRzX2RmIDwtIGFzLmRhdGEuZnJhbWUodGFibGUoZXZlbnRzX2RmKSkKZXZlbnRzX2RmIDwtIGFycmFuZ2UoZXZlbnRzX2RmLCBkZXNjKEZyZXEpKQpldmVudHNfZGYgPC0gaGVhZChldmVudHNfZGYsIDEwKQoKcDE0IDwtIGdncGxvdChkYXRhID0gZXZlbnRzX2RmLCBhZXMoZXZlbnQsIEZyZXEpKSArCiAgICAgIGdlb21fYmFyKHBvc2l0aW9uID0gImRvZGdlIiwgc3RhdCA9ICJpZGVudGl0eSIsIGNvbG9yID0gImJsdWUiLCBmaWxsPSJibHVlIikgKwogICAgICBnZW9tX3RleHQoYWVzKGxhYmVsID0gRnJlcSksIHZqdXN0ID0gMS42LCBjb2xvciA9ICJ3aGl0ZSIsIHNpemUgPSAzKSArCiAgICAgIHRpbHRfdGhlbWUKcDE0CmBgYAoKQXMgZXhwZWN0ZWQsIHRoZSBvZmZpY2lhbCBURUQgZXZlbnRzIGhlbGQgdGhlIG1ham9yIHNoYXJlIG9mIFRFRCBUYWxrcyBwdWJsaXNoZWQgb24gdGhlIFRFRC5jb20gcGxhdGZvcm0uIFRFRDIwMTQgaGFkIHRoZSBtb3N0IG51bWJlciBvZiB0YWxrcyBmb2xsb3dlZCBieSBURUQyMDA5LiBUaGVyZSBpc24ndCB0b28gbXVjaCBpbnNpZ2h0IHRvIGJlIGdhaW5lZCBmcm9tIHRoaXMuCgojIyMjIyMjIyMjIyMjIwpURUQgTGFuZ3VhZ2VzCk9uZSByZW1hcmthYmxlIGFzcGVjdCBvZiBURUQgVGFsa3MgaXMgdGhlIHNoZWVyIG51bWJlciBvZiBsYW5ndWFnZXMgaW4gd2hpY2ggaXQgaXMgYWNjZXNzaWJsZS4gTGV0IHVzIHBlcmZvcm0gc29tZSB2ZXJ5IGJhc2ljIGRhdGEgdmlzdWFsaXNhdGlvbiBhbmQgZGVzY3JpcHRpdmUgc3RhdGlzdGljcyBhYm91dCBsYW5ndWFnZXMgYXQgVEVELgoKYGBge3J9CmRlc2NyaWJlKHRlZCRsYW5ndWFnZXMpCmBgYAoKT24gYXZlcmFnZSwgYSBURUQgVGFsayBpcyBhdmFpbGFibGUgaW4gMjcgZGlmZmVyZW50IGxhbmd1YWdlcy4gVGhlIG1heGltdW0gbnVtYmVyIG9mIGxhbmd1YWdlcyBhIFRFRCBUYWxrIGlzIGF2YWlsYWJsZSBpbiBpcyBhIHN0YWdnZXJpbmcgNzIuIExldCB1cyBjaGVjayB3aGljaCB0YWxrIHRoaXMgaXMuCgpgYGB7cn0KZmlsdGVyKHRlZCwgdGVkJGxhbmd1YWdlcyA9PSA3MikKYGBgCgpUaGUgbW9zdCB0cmFuc2xhdGVkIFRFRCBUYWxrIG9mIGFsbCB0aW1lIGlzIE1hdHQgQ3V0dHMnIFRyeSBTb21ldGhpbmcgTmV3IGluIDMwIERheXMuIFRoZSB0YWxrIGRvZXMgaGF2ZSBhIHZlcnkgdW5pdmVyc2FsIHRoZW1lIG9mIGV4cGxvcmF0aW9uLiBUaGUgc2hlZXIgbnVtYmVyIG9mIGxhbmd1YWdlcyBpdCdzIGF2YWlsYWJsZSBpbiBkZW1hbmRzIGEgbGl0dGxlIG1vcmUgaW5zcGVjdGlvbiB0aG91Z2ggYXMgaXQgaGFzIGp1c3Qgb3ZlciA4IG1pbGxpb24gdmlld3MsIGZhciBmZXdlciB0aGFuIHRoZSBtb3N0IHBvcHVsYXIgVEVEIFRhbGtzLgoKRmluYWxseSwgbGV0IHVzIGNoZWNrIGlmIHRoZXJlIGlzIGEgY29ycmVsYXRpb24gYmV0d2VlbiB0aGUgbnVtYmVyIG9mIHZpZXdzIGFuZCB0aGUgbnVtYmVyIG9mIGxhbmd1YWdlcyBhIHRhbGsgaXMgYXZhaWxiYWxlIGluLiBXZSB3b3VsZCB0aGluayB0aGF0IHRoaXMgc2hvdWxkIGJlIHRoZSBjYXNlIHNpbmNlIHRoZSB0YWxrIGlzIG1vcmUgYWNjZXNzaWJsZSB0byBhIGxhcmdlciBudW1iZXIgb2YgcGVvcGxlIGJ1dCBhcyBNYXR0IEN1dHRzJyB0YWxrIHNob3dzLCBpdCBtYXkgbm90IHJlYWxseSBiZSB0aGUgY2FzZS4KCmBgYHtyfQpzY2F0dGVyMiA8LSBxcGxvdChsYW5ndWFnZXMsIHZpZXdzLCBkYXRhPXRlZCkgICsgCiAgICAgICAgIHNjYWxlX3lfY29udGludW91cyhsaW1pdHM9YyhtaW4odGVkJHZpZXdzKSxtYXgodGVkJHZpZXdzKSkpICsgCiAgICAgICAgIHNjYWxlX3hfY29udGludW91cyhsaW1pdHM9YyhtaW4odGVkJGxhbmd1YWdlcyksbWF4KHRlZCRsYW5ndWFnZXMpKSkgKyAKICAgICAgICAgZ2VvbV9ydWcoY29sPXJnYiguNSwwLDAsYWxwaGE9LjIpKQpzY2F0dGVyMgpgYGAKCmBgYHtyfQpjb3IodGVkJGxhbmd1YWdlcywgdGVkJHZpZXdzKQpgYGAKClRoZSBQZWFyc29uIGNvZWZmaWNpZW50IGlzIDAuMzggc3VnZ2VzdGluZyBhIG1lZGl1bSBjb3JyZWxhdGlvbiBiZXR3ZWVuIHRoZSBhZm9yZW1lbnRpb25lZCBxdWFudGl0aWVzLgoKIyMjIyMjIyMjIyMjIyMKVEVEIFRoZW1lcwpJbiB0aGlzIHNlY3Rpb24sIHdlIHdpbGwgdHJ5IHRvIGZpbmQgb3V0IHRoZSBtb3N0IHBvcHVsYXIgdGhlbWVzIGluIHRoZSBURUQgY29uZmVyZW5jZXMuIEFsdGhvdWdoIFRFRCBzdGFydGVkIG91dCBhcyBhIGNvbmZlcmVuY2UgYWJvdXQgdGVjaG5vbG9neSwgZW50ZXJ0YWlubWVudCBhbmQgZGVzaWduLCBpdCBoYXMgc2luY2UgZGl2ZXJzaWZpZWQgaW50byB2aXJ0dWFsbHkgZXZlcnkgZmllbGQgb2Ygc3R1ZHkgYW5kIHdhbGsgb2YgbGlmZS4gSXQgd2lsbCBiZSBpbnRlcmVzdGluZyB0byBzZWUgaWYgdGhpcyBjb25mZXJlbmNlIHdpdGggU2lsaWNvbiBWYWxsZXkgb3JpZ2lucyBoYXMgYSBiaWFzIHRvd2FyZHMgY2VydGFpbiB0b3BpY3MuCgpUbyBhbnN3ZXIgdGhpcyBxdWVzdGlvbiwgd2UgbmVlZCB0byB3cmFuZ2xlIG91ciBkYXRhIGluIGEgd2F5IHRoYXQgaXQgaXMgc3VpdGFibGUgZm9yIGFuYWx5c2lzLiBNb3JlIHNwZWNpZmljYWxseSwgd2UgbmVlZCB0byBzcGxpdCB0aGUgcmVsYXRlZF90YWdzIGxpc3QgaW50byBzZXBhcmF0ZSByb3dzLgoKYGBge3J9CnBlcmZlY3RfdGFnIDwtIGZ1bmN0aW9uKHgpewogIHggPC0gdW5saXN0KHN0cnNwbGl0KHgsICInIikpCiAgdmFsID0geFsyXQogIGZvciAoaSBpbiAzOmxlbmd0aCh4KSkKICAgIGlmIChuY2hhcih4W2ldKSA+MikKICAgICAgdmFsIDwtIGModmFsLCB4W2ldKQogICAgcmV0dXJuICh2YWwpCiAgCn0KdGVkJHByb2Nlc3NlZF90YWdzIDwtICBsYXBwbHkodGVkJHRhZ3MsIHBlcmZlY3RfdGFnKQpgYGAKCmBgYHtyfQpwcm9jZXNzZWRfdGFncyA8LSB0ZWQkcHJvY2Vzc2VkX3RhZ3MKbGVuZ3RoKHByb2Nlc3NlZF90YWdzKQpwcm9jZXNzZWRfdGFncyA8LSB1bmxpc3QocHJvY2Vzc2VkX3RhZ3MsIHJlY3Vyc2l2ZT1GQUxTRSkKbGVuZ3RoKHByb2Nlc3NlZF90YWdzKQpwcm9jZXNzZWRfdGFncyA8LSBhcy5kYXRhLmZyYW1lKHRhYmxlKHByb2Nlc3NlZF90YWdzKSkKcHJvY2Vzc2VkX3RhZ3MgPC0gYXJyYW5nZShwcm9jZXNzZWRfdGFncywgZGVzYyhGcmVxKSkKaGVhZChwcm9jZXNzZWRfdGFncywgMTApCmBgYAoKYGBge3J9CnByb2Nlc3NlZF90YWdzJHByb2Nlc3NlZF90YWdzIDwtIGFzLmNoYXJhY3Rlcihwcm9jZXNzZWRfdGFncyRwcm9jZXNzZWRfdGFncykKcHJvY2Vzc2VkX3RhZ3MkcHJvY2Vzc2VkX3RhZ3MgPC0gZmFjdG9yKHByb2Nlc3NlZF90YWdzJHByb2Nlc3NlZF90YWdzLCBsZXZlbHM9cHJvY2Vzc2VkX3RhZ3MkcHJvY2Vzc2VkX3RhZ3MpCnAxNSA8LSBnZ3Bsb3QoZGF0YSA9IGhlYWQocHJvY2Vzc2VkX3RhZ3MsIDEwKSwgYWVzKHByb2Nlc3NlZF90YWdzLCBGcmVxKSkgKwogICAgICBnZW9tX2Jhcihwb3NpdGlvbiA9ICJkb2RnZSIsIHN0YXQgPSAiaWRlbnRpdHkiLCBjb2xvciA9ICJibHVlIiwgZmlsbD0iYmx1ZSIpICsKICAgICAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IEZyZXEpLCB2anVzdCA9IDEuNiwgY29sb3IgPSAid2hpdGUiLCBzaXplID0gMykgKwogICAgICB0aWx0X3RoZW1lCnAxNQpgYGAKCkFzIG1heSBoYXZlIGJlZW4gZXhwZWN0ZWQsIFRlY2hub2xvZ3kgaXMgdGhlIG1vc3QgcG9wdWxhciB0b3BpYyBmb3IgdGFsa3MuIFRoZSBvdGhlciB0d28gb3JpZ2luYWwgZmFjdGlvbnMsIERlc2lnbiBhbmQgRW50ZXJ0YWlubWVudCwgYWxzbyBtYWtlIGl0IHRvIHRoZSBsaXN0IG9mIHRvcCAxMCB0aGVtZXMuIFNjaWVuY2UgYW5kIEdsb2JhbCBJc3N1ZXMgYXJlIHRoZSBzZWNvbmQgYW5kIHRoZSB0aGlyZCBtb3N0IHBvcHVsYXIgdGhlbWVzIHJlc3BlY3RpdmVseS4KClRoZSBuZXh0IHF1ZXN0aW9uIEkgd2FudCB0byBhbnN3ZXIgaXMgdGhlIHRyZW5kcyBpbiB0aGUgc2hhcmUgb2YgdG9waWNzIG9mIFRFRCBUYWxrcyBhY3Jvc3MgdGhlIHdvcmxkLiBIYXMgdGhlIGRlbWFuZCBmb3IgVGVjaG5vbG9neSB0YWxrcyBpbmNyZWFzZWQ/IERvIGNlcnRhaW4geWVhcnMgaGF2ZSBhIGRpc3Byb3BvcnRpb25hdGUgc2hhcmUgb2YgdGFsa3MgcmVsYXRlZCB0byBnbG9iYWwgaXNzdWVzPyBMZXQncyBmaW5kIG91dCEKCldlIHdpbGwgb25seSBiZSBjb25zaWRlcmluZyB0aGUgdG9wIDcgdGhlbWVzLCBleGNsdWRpbmcgVEVEeCBhbmQgdGFsa3MgYWZ0ZXIgMjAwOSwgdGhlIHllYXIgd2hlbiB0aGUgbnVtYmVyIG9mIFRFRCBUYWxrcyByZWFsbHkgcGVha2VkLgoKYGBge3J9CmZhY3Rvcl9mbiA8LSBmdW5jdGlvbih4KXsKICByZXR1cm4oZmFjdG9yKHgsIGxldmVscyA9IHgpKQp9CnRlZCRwcm9jZXNzZWRfdGFncyA8LSBsYXBwbHkodGVkJHByb2Nlc3NlZF90YWdzLCB1bmxpc3QsIHJlY3Vyc2l2ZSA9IEZBTFNFKQp0ZWQkcHJvY2Vzc2VkX3RhZ3MgPC0gbGFwcGx5KHRlZCRwcm9jZXNzZWRfdGFncywgZmFjdG9yX2ZuKQpyb3dzX3RvX2tlZXAgPC0gcmVwKFRSVUUsIGxlbmd0aCh0ZWQkcHJvY2Vzc2VkX3RhZ3MpKQpmb3IgKGkgaW4gMTpsZW5ndGgodGVkJHByb2Nlc3NlZF90YWdzKSl7CiAgaWYgKGFueSh1bmxpc3QodGVkJHByb2Nlc3NlZF90YWdzW2ldKSAlaW4lIHByb2Nlc3NlZF90YWdzJHByb2Nlc3NlZF90YWdzWzE6MTBdKSl7CiAgICByb3dzX3RvX2tlZXBbaV0gPC0gVFJVRX0gZWxzZSB7CiAgICByb3dzX3RvX2tlZXBbaV0gPC0gRkFMU0V9Cn0KYGBgCgoKYGBge3J9CnBvcF90aGVtZV90YWxrcyA8LSBzdWJzZXQocG9wX3RoZW1lX3RhbGtzLCBmaWxtaW5nX3llYXI+MjAwOCkKcG9wX3RoZW1lX3RhbGtzIDwtIHBvcF90aGVtZV90YWxrc1tyb3dzX3RvX2tlZXAsXQoKYGBgCmBgYHtyfQp0aGVtZXMgPC0gbGlzdChwcm9jZXNzZWRfdGFncyRwcm9jZXNzZWRfdGFnc1sxOjEwXSkKdGhlbWVzCmBgYAoKYGBge3J9CmNvbG5hbWVzKHBvcF90aGVtZV90YWxrcykKYGBgCgpgYGB7cn0KIyBkcm9wIGNvbHVtbnMKcG9wX3RoZW1lX3RhbGtzIDwtIHBvcF90aGVtZV90YWxrc1ssIGMoIm5hbWUiLCAiZXZlbnQiLCAidmlld3MiLCAiZmlsbWluZ19tb250aCIsICJmaWxtaW5nX3llYXIiLCAicHJvY2Vzc2VkX3RhZ3MiKV0KcG9wX3RoZW1lX3RhbGtzCmBgYApgYGB7cn0KeCA8LSB1bmxpc3QocG9wX3RoZW1lX3RhbGtzJHByb2Nlc3NlZF90YWdzWzRdKQp0b1N0cmluZyh4WzNdKQpgYGAKCmBgYHtyfQojdGFnIDwtICJ0ZWNobm9sb2d5IgojdGFnIDwtICJzY2llbmNlIgojdGFnIDwtICJnbG9iYWwgaXNzdWVzIgojdGFnIDwtICJjdWx0dXJlIgojdGFnIDwtICAiVEVEeCIKI3RhZyA8LSAiZGVzaWduIgojdGFnIDwtICJidXNpbmVzcyIKI3RhZyA8LSAgImVudGVydGFpbm1lbnQiCiN0YWcgPC0gImhlYWx0aCIKI3RhZyA8LSAiaW5ub3ZhdGlvbiIiCmNvdW50X3RhZyA8LSBmdW5jdGlvbih2ZWMsIHRhZyl7CiAgY291bnQgPC0gMAogIHg8LSB1bmxpc3QodmVjKQogIGZvciAoaSBpbiAxOmxlbmd0aCh4KSl7CiAgICBpZiAodG9TdHJpbmcoeFtpXSkgPT0gdGFnKXsKICAgICAgY291bnQgPC0gY291bnQrMQogICAgfQogIH0KICByZXR1cm4gKGNvdW50KQp9CgoKYGBgCgpgYGB7cn0KcG9wX3RoZW1lX3RhbGtzJHRlY2hub2xvZ3kgPC0gc2FwcGx5KFggPSBwb3BfdGhlbWVfdGFsa3MkcHJvY2Vzc2VkX3RhZ3MsRlVOID0gY291bnRfdGFnLCB0YWcgPSAidGVjaG5vbG9neSIpCgpwb3BfdGhlbWVfdGFsa3Mkc2NpZW5jZSA8LSBzYXBwbHkoWCA9IHBvcF90aGVtZV90YWxrcyRwcm9jZXNzZWRfdGFncyxGVU4gPSBjb3VudF90YWcsIHRhZyA9ICJzY2llbmNlIikKCnBvcF90aGVtZV90YWxrcyRnaSA8LSBzYXBwbHkoWCA9IHBvcF90aGVtZV90YWxrcyRwcm9jZXNzZWRfdGFncyxGVU4gPSBjb3VudF90YWcsIHRhZyA9ICJnbG9iYWwgaXNzdWVzIikKCnBvcF90aGVtZV90YWxrcyRjdWx0dXJlIDwtIHNhcHBseShYID0gcG9wX3RoZW1lX3RhbGtzJHByb2Nlc3NlZF90YWdzLEZVTiA9IGNvdW50X3RhZywgdGFnID0gImN1bHR1cmUiKQoKcG9wX3RoZW1lX3RhbGtzJHRlZHggPC0gc2FwcGx5KFggPSBwb3BfdGhlbWVfdGFsa3MkcHJvY2Vzc2VkX3RhZ3MsRlVOID0gY291bnRfdGFnLCB0YWcgPSAiVEVEeCIpCgpwb3BfdGhlbWVfdGFsa3MkZGVzaWduIDwtIHNhcHBseShYID0gcG9wX3RoZW1lX3RhbGtzJHByb2Nlc3NlZF90YWdzLEZVTiA9IGNvdW50X3RhZywgdGFnID0gImRlc2lnbiIpCgpwb3BfdGhlbWVfdGFsa3MkYnVzaW5lc3MgPC0gc2FwcGx5KFggPSBwb3BfdGhlbWVfdGFsa3MkcHJvY2Vzc2VkX3RhZ3MsRlVOID0gY291bnRfdGFnLCB0YWcgPSAiYnVzaW5lc3MiKQoKcG9wX3RoZW1lX3RhbGtzJGV0IDwtIHNhcHBseShYID0gcG9wX3RoZW1lX3RhbGtzJHByb2Nlc3NlZF90YWdzLEZVTiA9IGNvdW50X3RhZywgdGFnID0gImVudGVydGFpbm1lbnQiKQoKcG9wX3RoZW1lX3RhbGtzJGhlYWx0aCA8LSBzYXBwbHkoWCA9IHBvcF90aGVtZV90YWxrcyRwcm9jZXNzZWRfdGFncyxGVU4gPSBjb3VudF90YWcsIHRhZyA9ICJoZWFsdGgiKQoKcG9wX3RoZW1lX3RhbGtzJGlubm8gPC0gc2FwcGx5KFggPSBwb3BfdGhlbWVfdGFsa3MkcHJvY2Vzc2VkX3RhZ3MsRlVOID0gY291bnRfdGFnLCB0YWcgPSAiaW5ub3ZhdGlvbiIpCgpgYGAKCmBgYHtyfQp0YWcxIDwtIGFzLmRhdGEuZnJhbWUodGFibGUocG9wX3RoZW1lX3RhbGtzJGZpbG1pbmdfeWVhciwgcG9wX3RoZW1lX3RhbGtzJHRlY2hub2xvZ3kpWywyXSkKdGFnMiA8LSBhcy5kYXRhLmZyYW1lKHRhYmxlKHBvcF90aGVtZV90YWxrcyRmaWxtaW5nX3llYXIsIHBvcF90aGVtZV90YWxrcyRzY2llbmNlKVssMl0pCnRhZzMgPC0gYXMuZGF0YS5mcmFtZSh0YWJsZShwb3BfdGhlbWVfdGFsa3MkZmlsbWluZ195ZWFyLCBwb3BfdGhlbWVfdGFsa3MkZ2kpWywyXSkKdGFnNCA8LSBhcy5kYXRhLmZyYW1lKHRhYmxlKHBvcF90aGVtZV90YWxrcyRmaWxtaW5nX3llYXIsIHBvcF90aGVtZV90YWxrcyRjdWx0dXJlKVssMl0pCnRhZzUgPC0gYXMuZGF0YS5mcmFtZSh0YWJsZShwb3BfdGhlbWVfdGFsa3MkZmlsbWluZ195ZWFyLCBwb3BfdGhlbWVfdGFsa3MkdGVkeClbLDJdKQp0YWc2IDwtIGFzLmRhdGEuZnJhbWUodGFibGUocG9wX3RoZW1lX3RhbGtzJGZpbG1pbmdfeWVhciwgcG9wX3RoZW1lX3RhbGtzJGRlc2lnbilbLDJdKQp0YWc3IDwtIGFzLmRhdGEuZnJhbWUodGFibGUocG9wX3RoZW1lX3RhbGtzJGZpbG1pbmdfeWVhciwgcG9wX3RoZW1lX3RhbGtzJGJ1c2luZXNzKVssMl0pCnRhZzggPC0gYXMuZGF0YS5mcmFtZSh0YWJsZShwb3BfdGhlbWVfdGFsa3MkZmlsbWluZ195ZWFyLCBwb3BfdGhlbWVfdGFsa3MkZXQpWywyXSkKdGFnOSA8LSBhcy5kYXRhLmZyYW1lKHRhYmxlKHBvcF90aGVtZV90YWxrcyRmaWxtaW5nX3llYXIsIHBvcF90aGVtZV90YWxrcyRoZWFsdGgpWywyXSkKdGFnMTAgPC0gYXMuZGF0YS5mcmFtZSh0YWJsZShwb3BfdGhlbWVfdGFsa3MkZmlsbWluZ195ZWFyLCBwb3BfdGhlbWVfdGFsa3MkaW5ubylbLDJdKQpgYGAKCmBgYHtyfQp0YWdfZGYgPC0gY2JpbmQuZGF0YS5mcmFtZSh0YWcxLCB0YWcyLCB0YWczLCB0YWc0LCB0YWc1LCB0YWc2LCB0YWc3LCB0YWc4LCB0YWc5LCB0YWcxMCkKI3RhZ19kZiRmaWxtaW5nX3llYXIgPC0gYXMubnVtZXJpYyhyb3duYW1lcyh0YWdfZGYpKQoKdGFnX2RmIDwtIGFzLmRhdGEuZnJhbWUodCh0YWdfZGYpKQojY29sbmFtZXModGFnX2RmKSA8LSB0YWdfZGZbMSwgXQojdGFnX2RmPC0gdGFnX2RmWy0xLCBdCiN0YWdfZGYkbXlmYWN0b3IgPC0gZmFjdG9yKHJvdy5uYW1lcyh0YWdfZGYpKQp0YWdfZGYKYGBgCgpgYGB7cn0KbGlicmFyeShyZXNoYXBlMikKbGlicmFyeSAoc2NhbGVzKQp0YWdfZGYkcm93IDwtIHNlcV9sZW4obnJvdyh0YWdfZGYpKQpkYXQyIDwtIG1lbHQodGFnX2RmLCBpZC52YXJzID0gInJvdyIpCmRhdDIkdGFnIDwtIHJlcChjKCJ0ZWNobm9sb2d5Iiwic2NpZW5jZSIsImdsb2JhbCBpc3N1ZXMiLCAiY3VsdHVyZSIsICJURUR4IiwgImRlc2lnbiIsICJidXNpbmVzcyIsICJlbnRlcnRhaW5tZW50IiwKICAgICAgICAgICAgICAgICAgImhlYWx0aCIsImlubm92YXRpb24iKSwgOSkKcDE2IDwtIGdncGxvdChkYXQyLCBhZXMoeD12YXJpYWJsZSwgeT12YWx1ZSwgZmlsbD10YWcpKSArIAogIGdlb21fYmFyKHN0YXQ9ImlkZW50aXR5IiwgcG9zaXRpb24gPSAiZmlsbCIpICsKICB4bGFiKCJcblllYXIiKSArCiAgeWxhYigiUGVyY2VudGFnZVxuIikgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBwZXJjZW50X2Zvcm1hdCgpKSArCiAgdGlsdF90aGVtZQpwMTYKYGBgCmBgYHtyfQpoZWFkKGRhdDIpCmBgYAoKYGBge3J9CnAxNyA8LSBnZ3Bsb3QoZGF0MiwgYWVzKHg9dmFyaWFibGUsIHk9dmFsdWUsIGNvbG91cj10YWcpKSArIAogIGdlb21fcG9pbnQoYWVzKHg9dmFyaWFibGUsIHk9dmFsdWUsIGNvbG9yPXRhZywgc2l6ZSA9IHRhZykpICsKICB0aWx0X3RoZW1lCnAxNwpgYGAKClRoZSBwcm9wb3J0aW9uIG9mIHRlY2hub2xvZ3kgdGFsa3MgaGFzIHN0ZWFkaWx5IGluY3JlYXNlZCBvdmVyIHRoZSB5ZWFycyB3aXRoIGEgc2xpZ2h0IGRpcCBpbiAyMDEwLiBUaGlzIGlzIHVuZGVyc3RhbmRhYmxlIGNvbnNpZGVyaW5nIHRoZSBib29tIG9mIHRlY2hub2xvZ2llcyBzdWNoIGFzIGJsb2NrY2hhaW4sIGRlZXAgbGVhcm5pbmcgYW5kIGF1Z21lbnRlZCByZWFsaXR5IGNhcHR1cmluZyBwZW9wbGUncyBpbWFnaW5hdGlvbi4KClRhbGtzIG9uIGN1bHR1cmUgaGF2ZSB3aXRuZXNzZWQgYSBkaXAsIGRlY3JlYXNpbmcgc3RlYWRpbHkgc3RhcnRpbmcgMjAxMy4gVGhlIHNoYXJlIG9mIGN1bHR1cmUgdGFsa3MgaGFzIGJlZW4gdGhlIGxlYXN0IGluIDIwMTcuIEVudGVydGFpbm1lbnQgdGFsa3MgYWxzbyBzZWVtIHRvIGhhdmUgd2l0bmVzc2VkIGEgc2xpZ2h0IGRlY2xpbmUgaW4gcG9wdWxhcml0eSBzaW5jZSAyMDA5LgoKIyMjIyMjIyMjIyMjIyMKVGFsayBEdXJhdGlvbiBhbmQgV29yZCBDb3VudHMKCkluIHRoaXMgc2VjdGlvbiwgd2Ugd2lsbCBwZXJmb3JtIGFuYWx5c2lzIG9uIHRoZSBsZW5ndGggb2YgVEVEIFRhbGtzLiBURUQgaXMgZmFtb3VzIGZvciBpbXBvc2luZyBhIHZlcnkgc3RyaWN0IHRpbWUgbGltaXQgb2YgMTggbWludXRlcy4gQWx0aG91Z2ggdGhpcyBpcyB0aGUgc3VnZ2VzdGVkIGxpbWl0LCB0aGVyZSBoYXZlIGJlZW4gdGFsa3MgYXMgc2hvcnQgYXMgMiBtaW51dGVzIGFuZCBzb21lIGhhdmUgc3RyZXRjaGVkIHRvIGFzIGxvbmcgYXMgMjQgbWludXRlcy4gTGV0IHVzIGdldCBhbiBpZGVhIG9mIHRoZSBkaXN0cmlidXRpb24gb2YgVEVEIFRhbGsgZHVyYXRpb25zLgoKYGBge3J9CnRlZCRkdXJhdGlvbiA8LSB0ZWQkZHVyYXRpb24gLzYwCmRlc2NyaWJlKHRlZCRkdXJhdGlvbikKYGBgCgpURUQgVGFsa3MsIG9uIGF2ZXJhZ2UgYXJlIDEzLjcgbWludXRlcyBsb25nLiBJIGZpbmQgdGhpcyBzdGF0aXN0aWMgc3VycHJpc2luZyBiZWNhdXNlIFRFRCBUYWxrcyBhcmUgb2Z0ZW4gc3lub255bW91cyB3aXRoIDE4IG1pbnV0ZXMgYW5kIHRoZSBhdmVyYWdlIGlzIGEgZ29vZCAzIG1pbnV0ZXMgc2hvcnRlciB0aGFuIHRoYXQuCgpUaGUgc2hvcnRlc3QgVEVEIFRhbGsgb24gcmVjb3JkIGlzIDIuMjUgbWludXRlcyBsb25nIHdoZXJlYXMgdGhlIGxvbmdlc3QgdGFsayBpcyA4Ny42IG1pbnV0ZXMgbG9uZy4gSSdtIHByZXR0eSBzdXJlIHRoZSBsb25nZXN0IHRhbGsgd2FzIG5vdCBhY3R1YWxseSBhIFRFRCBUYWxrLiBMZXQgdXMgbG9vayBhdCBib3RoIHRoZSBzaG9ydGVzdCBhbmQgdGhlIGxvbmdlc3QgdGFsawoKYGBge3J9CmZpbHRlcih0ZWQsIHRlZCRkdXJhdGlvbiA9PSAyLjI1KQpgYGAKCmBgYHtyfQpmaWx0ZXIodGVkLCB0ZWQkZHVyYXRpb24gPT0gMi4yNSkKYGBgCgpUaGUgc2hvcnRlc3QgdGFsayB3YXMgYXQgVEVEMjAwNyB0aXRsZWQgVGhlIGFuY2VzdG9yIG9mIGxhbmd1YWdlIGJ5IE11cnJheSBHZWxsLU1hbm4uIFRoZSBsb25nZXN0IHRhbGsgb24gVEVELmNvbSwgYXMgd2UgaGFkIGd1ZXNzZWQsIGlzIG5vdCBhIFRFRCBUYWxrIGF0IGFsbC4gUmF0aGVyLCBpdCB3YXMgYSB0YWxrIHRpdGxlZCBQYXJyb3RzLCB0aGUgdW5pdmVyc2UgYW5kIGV2ZXJ5dGhpbmcgZGVsaXZlcmVkIGJ5IERvdWdsYXMgQWRhbXMgYXQgdGhlIFVuaXZlcnNpdHkgb2YgQ2FsaWZvcm5pYSBpbiAyMDAxLgoKTGV0IHVzIG5vdyBjaGVjayBmb3IgYW55IGNvcnJlbGF0aW9uIGJldHdlZW4gdGhlIHBvcHVsYXJpdHkgYW5kIHRoZSBkdXJhdGlvbiBvZiBhIFRFRCBUYWxrLiBUbyBtYWtlIHN1cmUgd2Ugb25seSBpbmNsdWRlIFRFRCBUYWxrcywgd2Ugd2lsbCBjb25zaWRlciBvbmx5IHRob3NlIHRhbGtzIHdoaWNoIGhhdmUgYSBkdXJhdGlvbiBsZXNzIHRoYW4gMjUgbWludXRlcwoKYGBge3J9CnNjYXR0ZXIzIDwtIHFwbG90KGR1cmF0aW9uLCB2aWV3cywgZGF0YT1maWx0ZXIodGVkLCB0ZWQkZHVyYXRpb24gPCAyNSkpICArIAogICAgICAgICBzY2FsZV95X2NvbnRpbnVvdXMobGltaXRzPWMobWluKHRlZCR2aWV3cyksbWF4KHRlZCR2aWV3cykpKSArIAogICAgICAgICBzY2FsZV94X2NvbnRpbnVvdXMobGltaXRzPWMobWluKHRlZCRkdXJhdGlvbiksMjUpKSArIAogICAgICAgICBnZW9tX3J1Zyhjb2w9cmdiKC41LDAsMCxhbHBoYT0uMikpCnNjYXR0ZXIzCmBgYApgYGB7cn0KeiA8LSBmaWx0ZXIodGVkLCB0ZWQkZHVyYXRpb24gPDI1KQp2ZF9jb3IgPC0gY29yKHokdmlld3MsIHokZHVyYXRpb24pCnByaW50KCJDb3JyZWxhdGlvbiBiZXR3ZWVuIFZpZXdzIGFuZCBkdXJhdGlvbiIpCnZkX2NvcgpgYGAKClRoZXJlIHNlZW1zIHRvIGJlIGFsbW9zdCBubyBjb3JyZWxhdGlvbiBiZXR3ZWVuIHRoZXNlIHR3byBxdWFudGl0aWVzLiBUaGlzIHN0cm9uZ2x5IHN1Z2dlc3RzIHRoYXQgdGhlcmUgaXMgbm8gdGFuZ2libGUgY29ycmVsYXRpb24gYmV0d2VlbiB0aGUgbGVuZ3RoIGFuZCB0aGUgcG9wdWxhcml0eSBvZiBhIFRFRCBUYWxrLiBDb250ZW50IGlzIGtpbmcgYXQgVEVELgoKTmV4dCwgd2UgbG9vayBhdCB0cmFuc2NyaXB0cyB0byBnZXQgYW4gaWRlYSBvZiB3b3JkIGNvdW50LiBGb3IgdGhpcywgd2UgaW50cm9kdWNlIG91ciBzZWNvbmQgZGF0YXNldCwgdGhlIG9uZSB3aGljaCBjb250YWlucyBhbGwgdHJhbnNjcmlwdHMuCgpgYGB7cn0KaGVhZCh0cmFuc2NyaXB0KQpgYGAKYGBge3J9CmRpbSh0cmFuc2NyaXB0KQpgYGAKCkl0IHNlZW1zIHRoYXQgd2UgaGF2ZSBkYXRhIGF2YWlsYWJsZSBmb3IgMjQ2NyB0YWxrcy4gTGV0IHVzIHBlcmZvcm0gYSBqb2luIG9mIHRoZSB0d28gZGF0YWZyYW1lcyBvbiB0aGUgdXJsIGZlYXR1cmUgdG8gaW5jbHVkZSB3b3JkIGNvdW50cyBmb3IgZXZlcnkgdGFsay4KCmBgYHtyfQpkZl90ZWQgPC0gbGVmdF9qb2luKHRlZCwgdHJhbnNjcmlwdCwgYnkgPSAidXJsIikKaGVhZChkZl90ZWQpCmBgYAoKYGBge3J9CmxpYnJhcnkoc3RyaW5ncikKZGZfdGVkJHRyYW5zY3JpcHQgPC0gcmVwbGFjZShkZl90ZWQkdHJhbnNjcmlwdCxpcy5uYShkZl90ZWQkdHJhbnNjcmlwdCksJyAnKQpjb3VudF93b3JkcyA8LSBmdW5jdGlvbih2ZWMpewogIHJldHVybiAobGVuZ3RoKHVubGlzdCgoc3RyX2V4dHJhY3RfYWxsKHRvbG93ZXIodmVjKSwgJ1xcdysnKSkpKSkKfQpkZl90ZWQkd29yZF9jb3VudCA8LSBzYXBwbHkoZGZfdGVkJHRyYW5zY3JpcHQsIGNvdW50X3dvcmRzKQoKYGBgCmBgYHtyfQpkZXNjcmliZShkZl90ZWQkd29yZF9jb3VudCkKYGBgCgpXZSBjYW4gc2VlIHRoYXQgdGhlIGF2ZXJhZ2UgVEVEIFRhbGsgaGFzIGFyb3VuZCAxOTcxIHdvcmRzIGFuZCB0aGVyZSBpcyBhIHNpZ25pZmljYW50bHkgbGFyZ2Ugc3RhbmRhcmQgZGV2aWF0aW9uIG9mIGEgMTAwOSB3b3Jkcy4gVGhlIGxvbmdlc3QgdGFsayBpcyBtb3JlIHRoYW4gOTA0NCB3b3JkcyBpbiBsZW5ndGguCgpMaWtlIGR1cmF0aW9uLCB0aGVyZSBzaG91bGRuJ3QgYmUgYW55IGNvcnJlbGF0aW9uIGJldHdlZW4gbnVtYmVyIG9mIHdvcmRzIGFuZCB2aWV3cy4gV2Ugd2lsbCBwcm9jZWVkIHRvIGxvb2sgYXQgYSBtb3JlIGludGVyZXN0aW5nIHN0YXRzdGljOiB0aGUgbnVtYmVyIG9mIHdvcmRzIHBlciBtaW51dGUuCgpgYGB7cn0KZGZfdGVkJHdwbSA8LSBkZl90ZWQkd29yZF9jb3VudC9kZl90ZWQkZHVyYXRpb24KZGVzY3JpYmUoZGZfdGVkJHdwbSkKYGBgCgpUaGUgYXZlcmFnZSBURUQgU3BlYWtlciBlbnVuY2lhdGVzIDE0MiB3b3JkcyBwZXIgbWludXRlLiBUaGUgZmFzdGVzdCB0YWxrZXIgc3Bva2UgYSBzdGFnZ2VyaW5nIDI0NyB3b3JkcyBhIG1pbnV0ZSB3aGljaCBpcyBtdWNoIGhpZ2hlciB0aGFuIHRoZSBhdmVyYWdlIG9mIDEyNS0xNTAgd29yZHMgcGVyIG1pbnV0ZSBpbiBFbmdsaXNoLiBMZXQgdXMgc2VlIHdobyB0aGlzIGlzIQoKYGBge3J9CmZpbHRlcihkZl90ZWQsIGRmX3RlZCR3cG0gPiAyNDUpCmBgYAoKRmluYWxseSwgaW4gdGhpcyBzZWN0aW9uLCBJJ2QgbGlrZSB0byBzZWUgaWYgdGhlcmUgaXMgYW55IGNvcnJlbGF0aW9uIGJldHdlZW4gd29yZHMgcGVyIG1pbnV0ZSBhbmQgcG9wdWxhcml0eS4KCmBgYHtyfQpzY2F0dGVyNCA8LSBxcGxvdCh3cG0sIHZpZXdzLCBkYXRhPWZpbHRlcihkZl90ZWQsIGRmX3RlZCRkdXJhdGlvbjwyNSkpICArIAogICAgICAgICBzY2FsZV95X2NvbnRpbnVvdXMobGltaXRzPWMobWluKGRmX3RlZCR2aWV3cyksbWF4KGRmX3RlZCR2aWV3cykpKSArIAogICAgICAgICBzY2FsZV94X2NvbnRpbnVvdXMobGltaXRzPWMobWluKGRmX3RlZCR3cG0pLG1heChkZl90ZWQkd3BtKSkpICsgCiAgICAgICAgIGdlb21fcnVnKGNvbD1yZ2IoLjUsMCwwLGFscGhhPS4yKSkKc2NhdHRlcjQKYGBgCgpgYGB7cn0KeiA8LSBmaWx0ZXIoZGZfdGVkLCBkZl90ZWQkZHVyYXRpb248MjUpCnZkX2NvciA8LSBjb3IoeiR2aWV3cywgeiR3cG0pCnByaW50KCJDb3JyZWxhdGlvbiBiZXR3ZWVuIFZpZXdzIGFuZCB3b3JkcyBwZXIgbWludXRlIikKdmRfY29yCmBgYAoKQWdhaW4sIHRoZXJlIGlzIHByYWN0aWNhbGx5IG5vIGNvcnJlbGF0aW9uLiBJZiB5b3UgYXJlIGdvaW5nIHRvIGdpdmUgYSBURUQgVGFsaywgeW91IHByb2JhYmx5IHNob3VsZG4ndCB3b3JyeSBpZiB5b3UncmUgc3BlYWtpbmcgYSBsaXR0bGUgZmFzdGVyIG9yIGEgbGl0dGxlIHNsb3dlciB0aGFuIHVzdWFsLgoKIyMjIyMjIyMjIyMjIwpURUQgUmF0aW5ncwpURUQgYWxsb3dzIGl0cyB1c2VycyB0byByYXRlIGEgcGFydGljdWxhciB0YWxrIG9uIGEgdmFyaWV0eSBvZiBtZXRyaWNzLiBXZSB0aGVyZWZvcmUgaGF2ZSBkYXRhIG9uIGhvdyBtYW55IHBlb3BsZSBmb3VuZCBhIHBhcnRpY3VsYXIgdGFsayBmdW5ueSwgaW5zcGlyaW5nLCBjcmVhdGl2ZSBhbmQgYSBteXJpYWQgb2Ygb3RoZXIgdmVyYnMuIExldCB1cyBpbnNwZWN0IGhvdyB0aGlzIHJhdGluZ3MgZGljdGlvbmFyeSBhY3R1YWxseSBsb29rcyBsaWtlLgoKYGBge3J9CnJhdGluZ190b19saXN0IDwtIGZ1bmN0aW9uKHZlYyl7CnggPC0gc3RyX2V4dHJhY3RfYWxsKHZlYywgIlxcdysiKQp4IDwtIHN0cl9yZXBsYWNlX2FsbCh4LCAiaWQiLCAiICIpCnggPC0gc3RyX3JlcGxhY2VfYWxsKHgsICJuYW1lIiwgIiAiKQp4IDwtIHN0cl9yZXBsYWNlX2FsbCh4LCAiY291bnQiLCAiICIpCnggPC0gdW5saXN0KHN0cl9leHRyYWN0X2FsbCh4LCAiXFx3KyIpKQp4IDwtIHNldGRpZmYoeCwgImMiKQpyZXR1cm4gKHgpCn0KYGBgCmBgYHtyfQp0ZWQkcmF0X2xpc3QgPC0gbGFwcGx5KHRlZCRyYXRpbmdzLCByYXRpbmdfdG9fbGlzdCkKYGBgCmBgYHtyfQp1bmxpc3QodGVkJHJhdF9saXN0WzFdKQp3aGljaCh1bmxpc3QodGVkJHJhdF9saXN0WzFdKSA9PSAiQmVhdXRpZnVsIikKdW5saXN0KHRlZCRyYXRfbGlzdFsxXSlbd2hpY2godW5saXN0KHRlZCRyYXRfbGlzdFsxXSkgPT0gIkJlYXV0aWZ1bCIpKzFdCmBgYAoKSW4gdGhpcyBzZWN0aW9uLCBJIHdhbnQgdG8gZmluZCBvdXQgd2hpY2ggdGFsa3Mgd2VyZSByYXRlZCB0aGUgZnVubmllc3QsIHRoZSBtb3N0IGJlYXV0aWZ1bCwgdGhlIG1vc3QgY29uZnVzaW5nIGFuZCBtb3N0IGphdyBkcm9wcGluZyBvZiBhbGwgdGltZS4gVGhlIHJlc3QgaXMgbGVmdCB0byB0aGUgcmVhZGVyIHRvIGV4cGxvcmUuIFdlIG5vdyBuZWVkIHRvIGRlZmluZSB0aHJlZSBleHRyYSBmZWF0dXJlcyB0byBhY2NvbXBsaXNoIHRoaXMgdGFzay4KCmBgYHtyfQpmaW5kX3JhdGluZ19jb3VudCA8LSBmdW5jdGlvbih2ZWMsIHJhdF90YWcpewogIGNvdW50IDwtIHVubGlzdCh2ZWMpW3doaWNoKHVubGlzdCh2ZWMpID09IHJhdF90YWcpICsxXQogIHJldHVybiAoY291bnQpCn0KYGBgCmBgYHtyfQp0ZWQkZnVubnkgPC0gc2FwcGx5KHRlZCRyYXRfbGlzdCwgZmluZF9yYXRpbmdfY291bnQsIHJhdF90YWcgPSAiRnVubnkiKQp0ZWQkZnVubnkgPC0gcmVwbGFjZSh0ZWQkZnVubnksaXMubmEodGVkJGZ1bm55KSwiMCIpCnRlZCRmdW5ueSA8LSBhcy5udW1lcmljKHRlZCRmdW5ueSkKdGVkJGZ1bm55IDwtIHJlcGxhY2UodGVkJGZ1bm55LGlzLm5hKHRlZCRmdW5ueSksMCkKCnRlZCRiZWF1dGlmdWwgPC0gc2FwcGx5KHRlZCRyYXRfbGlzdCwgZmluZF9yYXRpbmdfY291bnQsIHJhdF90YWcgPSAiQmVhdXRpZnVsIikKdGVkJGJlYXV0aWZ1bCA8LSByZXBsYWNlKHRlZCRiZWF1dGlmdWwsaXMubmEodGVkJGJlYXV0aWZ1bCksIjAiKQp0ZWQkYmVhdXRpZnVsIDwtIGFzLm51bWVyaWModGVkJGJlYXV0aWZ1bCkKdGVkJGJlYXV0aWZ1bCA8LSByZXBsYWNlKHRlZCRiZWF1dGlmdWwsaXMubmEodGVkJGJlYXV0aWZ1bCksMCkKCnRlZCRjb25mdXNpbmcgPC0gc2FwcGx5KHRlZCRyYXRfbGlzdCwgZmluZF9yYXRpbmdfY291bnQsIHJhdF90YWcgPSAiQ29uZnVzaW5nIikKdGVkJGNvbmZ1c2luZyA8LSByZXBsYWNlKHRlZCRjb25mdXNpbmcsaXMubmEodGVkJGNvbmZ1c2luZyksIjAiKQp0ZWQkY29uZnVzaW5nIDwtIGFzLm51bWVyaWModGVkJGNvbmZ1c2luZykKdGVkJGNvbmZ1c2luZyA8LSByZXBsYWNlKHRlZCRjb25mdXNpbmcsaXMubmEodGVkJGNvbmZ1c2luZyksMCkKCnRlZCRqYXdkcm9wcGluZyA8LSBzYXBwbHkodGVkJHJhdF9saXN0LCBmaW5kX3JhdGluZ19jb3VudCwgcmF0X3RhZyA9ICJkcm9wcGluZyIpCnRlZCRqYXdkcm9wcGluZyA8LSByZXBsYWNlKHRlZCRqYXdkcm9wcGluZyxpcy5uYSh0ZWQkamF3ZHJvcHBpbmcpLCIwIikKdGVkJGphd2Ryb3BwaW5nIDwtIGFzLm51bWVyaWModGVkJGphd2Ryb3BwaW5nKQp0ZWQkamF3ZHJvcHBpbmcgPC0gcmVwbGFjZSh0ZWQkamF3ZHJvcHBpbmcsaXMubmEodGVkJGphd2Ryb3BwaW5nKSwwKQpgYGAKYGBge3J9CmhlYWQodGVkKQpgYGAKCkZ1bm5pZXN0IHRhbGsgb2YgYWxsIHRpbWUKCmBgYHtyfQoKdGVuX3RhbGtzIDwtIGFycmFuZ2UodGVkLCBmdW5ueSkKa2VlcHMgPC0gYygidGl0bGUiLCAibWFpbl9zcGVha2VyIiwgInZpZXdzIiwgInNwZWFrZXJfb2NjdXBhdGlvbiIsICJmaWxtX2RhdGUiKQp0ZW5fdGFsa3MgPC0gc3Vic2V0KHRlbl90YWxrcywgc2VsZWN0ID0gYygidGl0bGUiLCAibWFpbl9zcGVha2VyIiwgInZpZXdzIiwgImZ1bm55IiwgImZpbG1fZGF0ZSIpKQoKbGFzdF8xMF90YWxrcyA8LSB0ZW5fdGFsa3NbMDoxMCxdCmxhc3RfMTBfdGFsa3MKCnRlbl90YWxrcyA8LSBhcnJhbmdlKHRlZCwgZGVzYyhmdW5ueSkpCnRlbl90YWxrcyA8LSBzdWJzZXQodGVuX3RhbGtzLCBzZWxlY3QgPSBjKCJ0aXRsZSIsICJtYWluX3NwZWFrZXIiLCAidmlld3MiLCAiZnVubnkiLCAiZmlsbV9kYXRlIikpCnRvcF8xMF90YWxrcyA8LSB0ZW5fdGFsa3NbMDoxMCxdCnRvcF8xMF90YWxrcwpgYGAKCk1vc3QgQmVhdXRpZnVsIFRhbGtzIG9mIGFsbCB0aW1lCgpgYGB7cn0KdGVuX3RhbGtzIDwtIGFycmFuZ2UodGVkLCBkZXNjKGJlYXV0aWZ1bCkpCnRlbl90YWxrcyA8LSBzdWJzZXQodGVuX3RhbGtzLCBzZWxlY3QgPSBjKCJ0aXRsZSIsICJtYWluX3NwZWFrZXIiLCAidmlld3MiLCAiYmVhdXRpZnVsIiwgImZpbG1fZGF0ZSIpKQp0b3BfMTBfdGFsa3MgPC0gdGVuX3RhbGtzWzA6MTAsXQp0b3BfMTBfdGFsa3MKYGBgCgpNb3N0IEphdyBEcm9wcGluZyBUYWxrcyBvZiBhbGwgdGltZQoKYGBge3J9CnRlbl90YWxrcyA8LSBhcnJhbmdlKHRlZCwgZGVzYyhqYXdkcm9wcGluZykpCnRlbl90YWxrcyA8LSBzdWJzZXQodGVuX3RhbGtzLCBzZWxlY3QgPSBjKCJ0aXRsZSIsICJtYWluX3NwZWFrZXIiLCAidmlld3MiLCAiamF3ZHJvcHBpbmciLCAiZmlsbV9kYXRlIikpCnRvcF8xMF90YWxrcyA8LSB0ZW5fdGFsa3NbMDoxMCxdCnRvcF8xMF90YWxrcwpgYGAKCk1vc3QgQ29uZnVzaW5nIFRhbGtzIG9mIGFsbCB0aW1lCgpgYGB7cn0KdGVuX3RhbGtzIDwtIGFycmFuZ2UodGVkLCBkZXNjKGNvbmZ1c2luZykpCnRlbl90YWxrcyA8LSBzdWJzZXQodGVuX3RhbGtzLCBzZWxlY3QgPSBjKCJ0aXRsZSIsICJtYWluX3NwZWFrZXIiLCAidmlld3MiLCAiY29uZnVzaW5nIiwgImZpbG1fZGF0ZSIpKQp0b3BfMTBfdGFsa3MgPC0gdGVuX3RhbGtzWzA6MTAsXQp0b3BfMTBfdGFsa3MKYGBgCgoKCg==